blob: 720143cacb2113343718420c01e25cd088f50b10 [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(),
anthonye5b39652012-04-21 05:37:29 +0000636 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000637 cache_info->filename);
638 return(MagickFalse);
639 }
cristy3dedf062011-07-02 14:07:40 +0000640 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000641 {
642 blob=(unsigned char *) RelinquishMagickMemory(blob);
643 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
644 cache_info->cache_filename);
645 return(MagickFalse);
646 }
cristy3dedf062011-07-02 14:07:40 +0000647 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000648 {
649 (void) ClosePixelCacheOnDisk(cache_info);
650 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000651 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
652 clone_info->cache_filename);
653 return(MagickFalse);
654 }
cristy4c08aed2011-07-01 19:47:50 +0000655 count=0;
656 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000657 {
cristy4c08aed2011-07-01 19:47:50 +0000658 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
659 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
660 blob);
661 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000662 {
cristy4c08aed2011-07-01 19:47:50 +0000663 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
664 cache_info->cache_filename);
665 break;
cristy3ed852e2009-09-05 21:47:34 +0000666 }
cristy4c08aed2011-07-01 19:47:50 +0000667 length=(size_t) count;
668 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
669 if ((MagickSizeType) count != length)
670 {
671 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
672 clone_info->cache_filename);
673 break;
674 }
675 }
676 (void) ClosePixelCacheOnDisk(clone_info);
677 (void) ClosePixelCacheOnDisk(cache_info);
678 blob=(unsigned char *) RelinquishMagickMemory(blob);
679 if (i < (MagickOffsetType) cache_info->length)
680 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000681 return(MagickTrue);
682}
683
cristyfd24a062012-01-02 14:46:34 +0000684static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000685 CacheInfo *cache_info,ExceptionInfo *exception)
686{
687 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000688 count;
cristy3ed852e2009-09-05 21:47:34 +0000689
cristy4c08aed2011-07-01 19:47:50 +0000690 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000691 {
cristy3ed852e2009-09-05 21:47:34 +0000692 /*
cristy4c08aed2011-07-01 19:47:50 +0000693 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000694 */
cristy4c08aed2011-07-01 19:47:50 +0000695 if (cache_info->debug != MagickFalse)
696 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
697 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
698 cache_info->length);
699 return(MagickTrue);
700 }
701 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
702 {
703 /*
704 Clone pixel cache (one cache on disk, one in memory).
705 */
706 if (cache_info->debug != MagickFalse)
707 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
708 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000709 {
cristy4c08aed2011-07-01 19:47:50 +0000710 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000711 cache_info->cache_filename);
712 return(MagickFalse);
713 }
cristy4c08aed2011-07-01 19:47:50 +0000714 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
715 cache_info->length,(unsigned char *) clone_info->pixels);
716 (void) ClosePixelCacheOnDisk(cache_info);
717 if ((MagickSizeType) count != cache_info->length)
718 {
719 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
720 cache_info->cache_filename);
721 return(MagickFalse);
722 }
723 return(MagickTrue);
724 }
725 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
726 {
727 /*
728 Clone pixel cache (one cache on disk, one in memory).
729 */
730 if (clone_info->debug != MagickFalse)
731 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
732 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
733 {
734 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
735 clone_info->cache_filename);
736 return(MagickFalse);
737 }
738 count=WritePixelCacheRegion(clone_info,clone_info->offset,
739 clone_info->length,(unsigned char *) cache_info->pixels);
740 (void) ClosePixelCacheOnDisk(clone_info);
741 if ((MagickSizeType) count != clone_info->length)
742 {
743 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
744 clone_info->cache_filename);
745 return(MagickFalse);
746 }
747 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000748 }
749 /*
cristy4c08aed2011-07-01 19:47:50 +0000750 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000751 */
cristy4c08aed2011-07-01 19:47:50 +0000752 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000753}
754
cristyfd24a062012-01-02 14:46:34 +0000755static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000756 CacheInfo *cache_info,ExceptionInfo *exception)
757{
cristy4c08aed2011-07-01 19:47:50 +0000758 MagickBooleanType
759 status;
cristy3ed852e2009-09-05 21:47:34 +0000760
cristy4c08aed2011-07-01 19:47:50 +0000761 MagickOffsetType
762 cache_offset,
763 clone_offset,
764 count;
765
766 register ssize_t
767 x;
768
cristyfd24a062012-01-02 14:46:34 +0000769 register unsigned char
770 *p;
771
cristy4c08aed2011-07-01 19:47:50 +0000772 size_t
cristy3ed852e2009-09-05 21:47:34 +0000773 length;
774
cristy4c08aed2011-07-01 19:47:50 +0000775 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000776 y;
777
cristy4c08aed2011-07-01 19:47:50 +0000778 unsigned char
779 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000780
cristy4c08aed2011-07-01 19:47:50 +0000781 /*
782 Clone pixel cache (unoptimized).
783 */
cristy3ed852e2009-09-05 21:47:34 +0000784 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000785 {
cristy4c08aed2011-07-01 19:47:50 +0000786 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
787 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
788 else
789 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
790 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
791 else
792 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
794 else
795 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
796 }
cristyed231572011-07-14 02:18:59 +0000797 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
798 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000799 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000800 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000801 if (blob == (unsigned char *) NULL)
802 {
803 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000804 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000805 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000806 return(MagickFalse);
807 }
cristy4c08aed2011-07-01 19:47:50 +0000808 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
809 cache_offset=0;
810 clone_offset=0;
811 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000814 {
cristy4c08aed2011-07-01 19:47:50 +0000815 blob=(unsigned char *) RelinquishMagickMemory(blob);
816 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000817 cache_info->cache_filename);
818 return(MagickFalse);
819 }
cristy4c08aed2011-07-01 19:47:50 +0000820 cache_offset=cache_info->offset;
821 }
822 if (clone_info->type == DiskCache)
823 {
cristy3dedf062011-07-02 14:07:40 +0000824 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000825 {
cristy4c08aed2011-07-01 19:47:50 +0000826 blob=(unsigned char *) RelinquishMagickMemory(blob);
827 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
828 clone_info->cache_filename);
829 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000830 }
cristy4c08aed2011-07-01 19:47:50 +0000831 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000832 }
833 /*
cristy4c08aed2011-07-01 19:47:50 +0000834 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000835 */
cristy4c08aed2011-07-01 19:47:50 +0000836 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000837 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000838 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000839 {
cristy4c08aed2011-07-01 19:47:50 +0000840 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000841 {
cristy9e0719b2011-12-29 03:45:45 +0000842 register ssize_t
843 i;
844
cristy3ed852e2009-09-05 21:47:34 +0000845 /*
cristy4c08aed2011-07-01 19:47:50 +0000846 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000847 */
cristyed231572011-07-14 02:18:59 +0000848 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000849 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000850 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000851 else
852 {
cristyfd24a062012-01-02 14:46:34 +0000853 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000854 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000855 {
cristy4c08aed2011-07-01 19:47:50 +0000856 status=MagickFalse;
857 break;
cristy3ed852e2009-09-05 21:47:34 +0000858 }
859 }
cristy4c08aed2011-07-01 19:47:50 +0000860 cache_offset+=length;
861 if ((y < (ssize_t) clone_info->rows) &&
862 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000863 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000864 {
cristy9e0719b2011-12-29 03:45:45 +0000865 PixelChannel
866 channel;
867
868 PixelTrait
869 traits;
870
871 ssize_t
872 offset;
873
cristy4c08aed2011-07-01 19:47:50 +0000874 /*
cristy3b8fe922011-12-29 18:56:23 +0000875 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000876 */
cristy9e0719b2011-12-29 03:45:45 +0000877 channel=clone_info->channel_map[i].channel;
878 traits=cache_info->channel_map[channel].traits;
879 if (traits == UndefinedPixelTrait)
880 {
cristy0f4425e2011-12-31 20:33:02 +0000881 clone_offset+=sizeof(Quantum);
882 continue;
cristy9e0719b2011-12-29 03:45:45 +0000883 }
cristy0f4425e2011-12-31 20:33:02 +0000884 offset=cache_info->channel_map[channel].offset;
885 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000886 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
887 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000888 else
889 {
cristy0f4425e2011-12-31 20:33:02 +0000890 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000891 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000892 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000893 {
cristy0f4425e2011-12-31 20:33:02 +0000894 status=MagickFalse;
895 break;
cristy4c08aed2011-07-01 19:47:50 +0000896 }
897 }
cristy9e0719b2011-12-29 03:45:45 +0000898 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000899 }
900 }
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));
cristye04362f2012-04-23 15:33:05 +0000903 if (y < clone_info->rows)
904 for ( ; x < (ssize_t) clone_info->columns; x++)
905 {
906 /*
907 Set remaining columns as undefined.
908 */
909 if (clone_info->type != DiskCache)
910 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
911 length);
912 else
913 {
914 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
915 if ((MagickSizeType) count != length)
916 {
917 status=MagickFalse;
918 break;
919 }
920 }
921 clone_offset+=length;
922 }
cristy4c08aed2011-07-01 19:47:50 +0000923 }
cristyed231572011-07-14 02:18:59 +0000924 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000925 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
926 for ( ; y < (ssize_t) clone_info->rows; y++)
927 {
928 /*
cristy9e0719b2011-12-29 03:45:45 +0000929 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000930 */
931 for (x=0; x < (ssize_t) clone_info->columns; x++)
932 {
933 if (clone_info->type != DiskCache)
934 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
935 length);
936 else
937 {
938 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
939 if ((MagickSizeType) count != length)
940 {
941 status=MagickFalse;
942 break;
943 }
944 }
945 clone_offset+=length;
946 }
947 }
cristy9e0719b2011-12-29 03:45:45 +0000948 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000949 (clone_info->metacontent_extent != 0))
950 {
951 /*
952 Clone metacontent.
953 */
954 for (y=0; y < (ssize_t) cache_info->rows; y++)
955 {
956 for (x=0; x < (ssize_t) cache_info->columns; x++)
957 {
958 /*
959 Read a set of metacontent.
960 */
961 length=cache_info->metacontent_extent;
962 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000963 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000964 else
965 {
cristyfd24a062012-01-02 14:46:34 +0000966 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000967 if ((MagickSizeType) count != length)
968 {
969 status=MagickFalse;
970 break;
971 }
972 }
973 cache_offset+=length;
974 if ((y < (ssize_t) clone_info->rows) &&
975 (x < (ssize_t) clone_info->columns))
976 {
977 /*
978 Write a set of metacontent.
979 */
980 length=clone_info->metacontent_extent;
981 if (clone_info->type != DiskCache)
982 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000983 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000984 else
985 {
cristyfd24a062012-01-02 14:46:34 +0000986 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000987 if ((MagickSizeType) count != length)
988 {
989 status=MagickFalse;
990 break;
991 }
992 }
993 clone_offset+=length;
994 }
995 }
996 length=clone_info->metacontent_extent;
997 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
998 for ( ; x < (ssize_t) clone_info->columns; x++)
999 {
1000 /*
cristy9e0719b2011-12-29 03:45:45 +00001001 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001002 */
1003 if (clone_info->type != DiskCache)
1004 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1005 blob,length);
1006 else
1007 {
cristy208b1002011-08-07 18:51:50 +00001008 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001009 if ((MagickSizeType) count != length)
1010 {
1011 status=MagickFalse;
1012 break;
1013 }
1014 }
1015 clone_offset+=length;
1016 }
1017 }
1018 length=clone_info->metacontent_extent;
1019 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
cristye04362f2012-04-23 15:33:05 +00001020 if (y < clone_info->rows)
1021 for ( ; y < (ssize_t) clone_info->rows; y++)
cristy4c08aed2011-07-01 19:47:50 +00001022 {
cristye04362f2012-04-23 15:33:05 +00001023 /*
1024 Set remaining rows as undefined.
1025 */
1026 for (x=0; x < (ssize_t) clone_info->columns; x++)
1027 {
1028 if (clone_info->type != DiskCache)
1029 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1030 blob,length);
1031 else
1032 {
1033 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1034 blob);
1035 if ((MagickSizeType) count != length)
1036 {
1037 status=MagickFalse;
1038 break;
1039 }
1040 }
1041 clone_offset+=length;
1042 }
cristy4c08aed2011-07-01 19:47:50 +00001043 }
cristy4c08aed2011-07-01 19:47:50 +00001044 }
1045 if (clone_info->type == DiskCache)
1046 (void) ClosePixelCacheOnDisk(clone_info);
1047 if (cache_info->type == DiskCache)
1048 (void) ClosePixelCacheOnDisk(cache_info);
1049 blob=(unsigned char *) RelinquishMagickMemory(blob);
1050 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001051}
1052
1053static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1054 CacheInfo *cache_info,ExceptionInfo *exception)
1055{
cristy3dfccb22011-12-28 21:47:20 +00001056 PixelChannelMap
1057 *p,
1058 *q;
1059
cristy5a7fbfb2010-11-06 16:10:59 +00001060 if (cache_info->type == PingCache)
1061 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001062 p=cache_info->channel_map;
1063 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001064 if ((cache_info->columns == clone_info->columns) &&
1065 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001066 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001067 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001068 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001069 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1070 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001071}
1072
1073/*
1074%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1075% %
1076% %
1077% %
1078+ C l o n e P i x e l C a c h e M e t h o d s %
1079% %
1080% %
1081% %
1082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1083%
1084% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1085% another.
1086%
1087% The format of the ClonePixelCacheMethods() method is:
1088%
1089% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1090%
1091% A description of each parameter follows:
1092%
1093% o clone: Specifies a pointer to a Cache structure.
1094%
1095% o cache: the pixel cache.
1096%
1097*/
cristya6577ff2011-09-02 19:54:26 +00001098MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001099{
1100 CacheInfo
1101 *cache_info,
1102 *source_info;
1103
1104 assert(clone != (Cache) NULL);
1105 source_info=(CacheInfo *) clone;
1106 assert(source_info->signature == MagickSignature);
1107 if (source_info->debug != MagickFalse)
1108 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1109 source_info->filename);
1110 assert(cache != (Cache) NULL);
1111 cache_info=(CacheInfo *) cache;
1112 assert(cache_info->signature == MagickSignature);
1113 source_info->methods=cache_info->methods;
1114}
1115
1116/*
1117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1118% %
1119% %
1120% %
1121+ D e s t r o y I m a g e P i x e l C a c h e %
1122% %
1123% %
1124% %
1125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126%
1127% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1128%
1129% The format of the DestroyImagePixelCache() method is:
1130%
1131% void DestroyImagePixelCache(Image *image)
1132%
1133% A description of each parameter follows:
1134%
1135% o image: the image.
1136%
1137*/
1138static void DestroyImagePixelCache(Image *image)
1139{
1140 assert(image != (Image *) NULL);
1141 assert(image->signature == MagickSignature);
1142 if (image->debug != MagickFalse)
1143 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1144 if (image->cache == (void *) NULL)
1145 return;
1146 image->cache=DestroyPixelCache(image->cache);
1147}
1148
1149/*
1150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1151% %
1152% %
1153% %
1154+ D e s t r o y I m a g e P i x e l s %
1155% %
1156% %
1157% %
1158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1159%
1160% DestroyImagePixels() deallocates memory associated with the pixel cache.
1161%
1162% The format of the DestroyImagePixels() method is:
1163%
1164% void DestroyImagePixels(Image *image)
1165%
1166% A description of each parameter follows:
1167%
1168% o image: the image.
1169%
1170*/
1171MagickExport void DestroyImagePixels(Image *image)
1172{
1173 CacheInfo
1174 *cache_info;
1175
1176 assert(image != (const Image *) NULL);
1177 assert(image->signature == MagickSignature);
1178 if (image->debug != MagickFalse)
1179 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1180 assert(image->cache != (Cache) NULL);
1181 cache_info=(CacheInfo *) image->cache;
1182 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001183 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1184 {
1185 cache_info->methods.destroy_pixel_handler(image);
1186 return;
1187 }
cristy2036f5c2010-09-19 21:18:17 +00001188 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001189}
1190
1191/*
1192%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1193% %
1194% %
1195% %
1196+ D e s t r o y P i x e l C a c h e %
1197% %
1198% %
1199% %
1200%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1201%
1202% DestroyPixelCache() deallocates memory associated with the pixel cache.
1203%
1204% The format of the DestroyPixelCache() method is:
1205%
1206% Cache DestroyPixelCache(Cache cache)
1207%
1208% A description of each parameter follows:
1209%
1210% o cache: the pixel cache.
1211%
1212*/
1213
1214static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1215{
1216 switch (cache_info->type)
1217 {
1218 case MemoryCache:
1219 {
1220 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001221 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001222 cache_info->pixels);
1223 else
cristy4c08aed2011-07-01 19:47:50 +00001224 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001225 (size_t) cache_info->length);
1226 RelinquishMagickResource(MemoryResource,cache_info->length);
1227 break;
1228 }
1229 case MapCache:
1230 {
cristy4c08aed2011-07-01 19:47:50 +00001231 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001232 cache_info->length);
1233 RelinquishMagickResource(MapResource,cache_info->length);
1234 }
1235 case DiskCache:
1236 {
1237 if (cache_info->file != -1)
1238 (void) ClosePixelCacheOnDisk(cache_info);
1239 RelinquishMagickResource(DiskResource,cache_info->length);
1240 break;
1241 }
1242 default:
1243 break;
1244 }
1245 cache_info->type=UndefinedCache;
1246 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001247 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001248}
1249
cristya6577ff2011-09-02 19:54:26 +00001250MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001251{
1252 CacheInfo
1253 *cache_info;
1254
cristy3ed852e2009-09-05 21:47:34 +00001255 assert(cache != (Cache) NULL);
1256 cache_info=(CacheInfo *) cache;
1257 assert(cache_info->signature == MagickSignature);
1258 if (cache_info->debug != MagickFalse)
1259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1260 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001261 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001262 cache_info->reference_count--;
1263 if (cache_info->reference_count != 0)
1264 {
cristyf84a1932010-01-03 18:00:18 +00001265 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001266 return((Cache) NULL);
1267 }
cristyf84a1932010-01-03 18:00:18 +00001268 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001269 if (cache_info->debug != MagickFalse)
1270 {
1271 char
1272 message[MaxTextExtent];
1273
cristyb51dff52011-05-19 16:55:47 +00001274 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001275 cache_info->filename);
1276 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1277 }
cristyc2e1bdd2009-09-10 23:43:34 +00001278 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1279 (cache_info->type != DiskCache)))
1280 RelinquishPixelCachePixels(cache_info);
1281 else
1282 {
1283 RelinquishPixelCachePixels(cache_info);
1284 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1285 }
cristy3ed852e2009-09-05 21:47:34 +00001286 *cache_info->cache_filename='\0';
1287 if (cache_info->nexus_info != (NexusInfo **) NULL)
1288 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1289 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001290 if (cache_info->random_info != (RandomInfo *) NULL)
1291 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001292 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1293 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1294 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1295 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001296 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001297 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001298 cache=(Cache) NULL;
1299 return(cache);
1300}
1301
1302/*
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304% %
1305% %
1306% %
1307+ D e s t r o y P i x e l C a c h e N e x u s %
1308% %
1309% %
1310% %
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312%
1313% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1314%
1315% The format of the DestroyPixelCacheNexus() method is:
1316%
1317% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001318% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001319%
1320% A description of each parameter follows:
1321%
1322% o nexus_info: the nexus to destroy.
1323%
1324% o number_threads: the number of nexus threads.
1325%
1326*/
1327
1328static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1329{
1330 if (nexus_info->mapped == MagickFalse)
cristy64c3edf2012-04-13 18:50:13 +00001331 (void) RelinquishMagickMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001332 else
1333 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001334 nexus_info->cache=(Quantum *) NULL;
1335 nexus_info->pixels=(Quantum *) NULL;
1336 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001337 nexus_info->length=0;
1338 nexus_info->mapped=MagickFalse;
1339}
1340
cristya6577ff2011-09-02 19:54:26 +00001341MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001342 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001343{
cristybb503372010-05-27 20:51:26 +00001344 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001345 i;
1346
1347 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001348 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001349 {
cristy4c08aed2011-07-01 19:47:50 +00001350 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001351 RelinquishCacheNexusPixels(nexus_info[i]);
1352 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001353 }
cristye5f87c82012-02-14 12:44:17 +00001354 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001355 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001356 return(nexus_info);
1357}
1358
1359/*
1360%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1361% %
1362% %
1363% %
cristy4c08aed2011-07-01 19:47:50 +00001364% 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 +00001365% %
1366% %
1367% %
1368%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1369%
cristy4c08aed2011-07-01 19:47:50 +00001370% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1371% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1372% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001373%
cristy4c08aed2011-07-01 19:47:50 +00001374% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001375%
cristy4c08aed2011-07-01 19:47:50 +00001376% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001377%
1378% A description of each parameter follows:
1379%
1380% o image: the image.
1381%
1382*/
cristy4c08aed2011-07-01 19:47:50 +00001383MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001384{
1385 CacheInfo
1386 *cache_info;
1387
cristy5c9e6f22010-09-17 17:31:01 +00001388 const int
1389 id = GetOpenMPThreadId();
1390
cristy4c08aed2011-07-01 19:47:50 +00001391 void
1392 *metacontent;
1393
cristye7cc7cf2010-09-21 13:26:47 +00001394 assert(image != (const Image *) NULL);
1395 assert(image->signature == MagickSignature);
1396 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001397 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001398 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001399 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1400 (GetAuthenticMetacontentFromHandler) NULL)
1401 {
1402 metacontent=cache_info->methods.
1403 get_authentic_metacontent_from_handler(image);
1404 return(metacontent);
1405 }
cristy6ebe97c2010-07-03 01:17:28 +00001406 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001407 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1408 cache_info->nexus_info[id]);
1409 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001410}
1411
1412/*
1413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414% %
1415% %
1416% %
cristy4c08aed2011-07-01 19:47:50 +00001417+ 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 +00001418% %
1419% %
1420% %
1421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422%
cristy4c08aed2011-07-01 19:47:50 +00001423% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1424% with the last call to QueueAuthenticPixelsCache() or
1425% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001426%
cristy4c08aed2011-07-01 19:47:50 +00001427% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001428%
cristy4c08aed2011-07-01 19:47:50 +00001429% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001430%
1431% A description of each parameter follows:
1432%
1433% o image: the image.
1434%
1435*/
cristy4c08aed2011-07-01 19:47:50 +00001436static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001437{
1438 CacheInfo
1439 *cache_info;
1440
cristy2036f5c2010-09-19 21:18:17 +00001441 const int
1442 id = GetOpenMPThreadId();
1443
cristy4c08aed2011-07-01 19:47:50 +00001444 void
1445 *metacontent;
1446
cristy3ed852e2009-09-05 21:47:34 +00001447 assert(image != (const Image *) NULL);
1448 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001449 assert(image->cache != (Cache) NULL);
1450 cache_info=(CacheInfo *) image->cache;
1451 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001452 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001453 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1454 cache_info->nexus_info[id]);
1455 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001456}
1457
1458/*
1459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1460% %
1461% %
1462% %
1463+ 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 %
1464% %
1465% %
1466% %
1467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1468%
1469% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1470% disk pixel cache as defined by the geometry parameters. A pointer to the
1471% pixels is returned if the pixels are transferred, otherwise a NULL is
1472% returned.
1473%
1474% The format of the GetAuthenticPixelCacheNexus() method is:
1475%
cristy4c08aed2011-07-01 19:47:50 +00001476% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001477% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001478% NexusInfo *nexus_info,ExceptionInfo *exception)
1479%
1480% A description of each parameter follows:
1481%
1482% o image: the image.
1483%
1484% o x,y,columns,rows: These values define the perimeter of a region of
1485% pixels.
1486%
1487% o nexus_info: the cache nexus to return.
1488%
1489% o exception: return any errors or warnings in this structure.
1490%
1491*/
1492
cristy4c08aed2011-07-01 19:47:50 +00001493static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001494 NexusInfo *nexus_info)
1495{
cristy4c08aed2011-07-01 19:47:50 +00001496 MagickBooleanType
1497 status;
1498
cristy3ed852e2009-09-05 21:47:34 +00001499 MagickOffsetType
1500 offset;
1501
cristy73724512010-04-12 14:43:14 +00001502 if (cache_info->type == PingCache)
1503 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001504 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1505 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001506 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001507 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001508 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001509}
1510
cristya6577ff2011-09-02 19:54:26 +00001511MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001512 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001513 NexusInfo *nexus_info,ExceptionInfo *exception)
1514{
1515 CacheInfo
1516 *cache_info;
1517
cristy4c08aed2011-07-01 19:47:50 +00001518 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001519 *q;
cristy3ed852e2009-09-05 21:47:34 +00001520
1521 /*
1522 Transfer pixels from the cache.
1523 */
1524 assert(image != (Image *) NULL);
1525 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001526 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1527 exception);
cristyacd2ed22011-08-30 01:44:23 +00001528 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001529 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001530 cache_info=(CacheInfo *) image->cache;
1531 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001532 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001533 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001534 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001535 return((Quantum *) NULL);
1536 if (cache_info->metacontent_extent != 0)
1537 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1538 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001539 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001540}
1541
1542/*
1543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1544% %
1545% %
1546% %
1547+ 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 %
1548% %
1549% %
1550% %
1551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552%
1553% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1554% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1555%
1556% The format of the GetAuthenticPixelsFromCache() method is:
1557%
cristy4c08aed2011-07-01 19:47:50 +00001558% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001559%
1560% A description of each parameter follows:
1561%
1562% o image: the image.
1563%
1564*/
cristy4c08aed2011-07-01 19:47:50 +00001565static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001566{
1567 CacheInfo
1568 *cache_info;
1569
cristy5c9e6f22010-09-17 17:31:01 +00001570 const int
1571 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001572
cristye7cc7cf2010-09-21 13:26:47 +00001573 assert(image != (const Image *) NULL);
1574 assert(image->signature == MagickSignature);
1575 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001576 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001577 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001578 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001579 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001580}
1581
1582/*
1583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1584% %
1585% %
1586% %
1587% G e t A u t h e n t i c P i x e l Q u e u e %
1588% %
1589% %
1590% %
1591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592%
cristy4c08aed2011-07-01 19:47:50 +00001593% GetAuthenticPixelQueue() returns the authentic pixels associated
1594% corresponding with the last call to QueueAuthenticPixels() or
1595% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001596%
1597% The format of the GetAuthenticPixelQueue() method is:
1598%
cristy4c08aed2011-07-01 19:47:50 +00001599% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001600%
1601% A description of each parameter follows:
1602%
1603% o image: the image.
1604%
1605*/
cristy4c08aed2011-07-01 19:47:50 +00001606MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001607{
1608 CacheInfo
1609 *cache_info;
1610
cristy2036f5c2010-09-19 21:18:17 +00001611 const int
1612 id = GetOpenMPThreadId();
1613
cristy3ed852e2009-09-05 21:47:34 +00001614 assert(image != (const Image *) NULL);
1615 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001616 assert(image->cache != (Cache) NULL);
1617 cache_info=(CacheInfo *) image->cache;
1618 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001619 if (cache_info->methods.get_authentic_pixels_from_handler !=
1620 (GetAuthenticPixelsFromHandler) NULL)
1621 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001622 assert(id < (int) cache_info->number_threads);
1623 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001624}
1625
1626/*
1627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1628% %
1629% %
1630% %
1631% G e t A u t h e n t i c P i x e l s %
1632% %
1633% %
cristy4c08aed2011-07-01 19:47:50 +00001634% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001635%
1636% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001637% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001638% representing the region is returned, otherwise NULL is returned.
1639%
1640% The returned pointer may point to a temporary working copy of the pixels
1641% or it may point to the original pixels in memory. Performance is maximized
1642% if the selected region is part of one row, or one or more full rows, since
1643% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001644% if the image is in memory, or in a memory-mapped file. The returned pointer
1645% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001646%
1647% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001648% Quantum. If the image has corresponding metacontent,call
1649% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1650% meta-content corresponding to the region. Once the Quantum array has
1651% been updated, the changes must be saved back to the underlying image using
1652% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001653%
1654% The format of the GetAuthenticPixels() method is:
1655%
cristy4c08aed2011-07-01 19:47:50 +00001656% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001657% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001658% ExceptionInfo *exception)
1659%
1660% A description of each parameter follows:
1661%
1662% o image: the image.
1663%
1664% o x,y,columns,rows: These values define the perimeter of a region of
1665% pixels.
1666%
1667% o exception: return any errors or warnings in this structure.
1668%
1669*/
cristy4c08aed2011-07-01 19:47:50 +00001670MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001671 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001672 ExceptionInfo *exception)
1673{
1674 CacheInfo
1675 *cache_info;
1676
cristy2036f5c2010-09-19 21:18:17 +00001677 const int
1678 id = GetOpenMPThreadId();
1679
cristy4c08aed2011-07-01 19:47:50 +00001680 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001681 *q;
cristy4c08aed2011-07-01 19:47:50 +00001682
cristy3ed852e2009-09-05 21:47:34 +00001683 assert(image != (Image *) NULL);
1684 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001685 assert(image->cache != (Cache) NULL);
1686 cache_info=(CacheInfo *) image->cache;
1687 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001688 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001689 (GetAuthenticPixelsHandler) NULL)
1690 {
cristyacd2ed22011-08-30 01:44:23 +00001691 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1692 exception);
1693 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001694 }
cristy2036f5c2010-09-19 21:18:17 +00001695 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001696 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001697 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001698 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001699}
1700
1701/*
1702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703% %
1704% %
1705% %
1706+ G e t A u t h e n t i c P i x e l s C a c h e %
1707% %
1708% %
1709% %
1710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1711%
1712% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1713% as defined by the geometry parameters. A pointer to the pixels is returned
1714% if the pixels are transferred, otherwise a NULL is returned.
1715%
1716% The format of the GetAuthenticPixelsCache() method is:
1717%
cristy4c08aed2011-07-01 19:47:50 +00001718% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001719% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001720% ExceptionInfo *exception)
1721%
1722% A description of each parameter follows:
1723%
1724% o image: the image.
1725%
1726% o x,y,columns,rows: These values define the perimeter of a region of
1727% pixels.
1728%
1729% o exception: return any errors or warnings in this structure.
1730%
1731*/
cristy4c08aed2011-07-01 19:47:50 +00001732static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001733 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001734 ExceptionInfo *exception)
1735{
1736 CacheInfo
1737 *cache_info;
1738
cristy5c9e6f22010-09-17 17:31:01 +00001739 const int
1740 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001741
cristy4c08aed2011-07-01 19:47:50 +00001742 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001743 *q;
cristy4c08aed2011-07-01 19:47:50 +00001744
cristye7cc7cf2010-09-21 13:26:47 +00001745 assert(image != (const Image *) NULL);
1746 assert(image->signature == MagickSignature);
1747 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001748 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001749 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001750 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001751 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001752 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001753 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001754 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001755 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001756}
1757
1758/*
1759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760% %
1761% %
1762% %
1763+ G e t I m a g e E x t e n t %
1764% %
1765% %
1766% %
1767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1768%
cristy4c08aed2011-07-01 19:47:50 +00001769% GetImageExtent() returns the extent of the pixels associated corresponding
1770% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001771%
1772% The format of the GetImageExtent() method is:
1773%
1774% MagickSizeType GetImageExtent(const Image *image)
1775%
1776% A description of each parameter follows:
1777%
1778% o image: the image.
1779%
1780*/
1781MagickExport MagickSizeType GetImageExtent(const Image *image)
1782{
1783 CacheInfo
1784 *cache_info;
1785
cristy5c9e6f22010-09-17 17:31:01 +00001786 const int
1787 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001788
cristy3ed852e2009-09-05 21:47:34 +00001789 assert(image != (Image *) NULL);
1790 assert(image->signature == MagickSignature);
1791 if (image->debug != MagickFalse)
1792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1793 assert(image->cache != (Cache) NULL);
1794 cache_info=(CacheInfo *) image->cache;
1795 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001796 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001797 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001798}
1799
1800/*
1801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802% %
1803% %
1804% %
1805+ G e t I m a g e P i x e l C a c h e %
1806% %
1807% %
1808% %
1809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1810%
1811% GetImagePixelCache() ensures that there is only a single reference to the
1812% pixel cache to be modified, updating the provided cache pointer to point to
1813% a clone of the original pixel cache if necessary.
1814%
1815% The format of the GetImagePixelCache method is:
1816%
1817% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1818% ExceptionInfo *exception)
1819%
1820% A description of each parameter follows:
1821%
1822% o image: the image.
1823%
1824% o clone: any value other than MagickFalse clones the cache pixels.
1825%
1826% o exception: return any errors or warnings in this structure.
1827%
1828*/
cristyaf894d72011-08-06 23:03:10 +00001829
cristy3ed852e2009-09-05 21:47:34 +00001830static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1831{
1832 CacheInfo
1833 *cache_info;
1834
cristy9e0719b2011-12-29 03:45:45 +00001835 PixelChannelMap
1836 *p,
1837 *q;
1838
cristy3ed852e2009-09-05 21:47:34 +00001839 /*
1840 Does the image match the pixel cache morphology?
1841 */
1842 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001843 p=image->channel_map;
1844 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001845 if ((image->storage_class != cache_info->storage_class) ||
1846 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001847 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001848 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001849 (image->columns != cache_info->columns) ||
1850 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001851 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001852 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001853 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001854 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1855 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1856 return(MagickFalse);
1857 return(MagickTrue);
1858}
1859
cristycd01fae2011-08-06 23:52:42 +00001860static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1861 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001862{
1863 CacheInfo
1864 *cache_info;
1865
cristy3ed852e2009-09-05 21:47:34 +00001866 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001867 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001868 status;
1869
cristy50a10922010-02-15 18:35:25 +00001870 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001871 cpu_throttle = 0,
1872 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001873 time_limit = 0;
1874
cristy1ea34962010-07-01 19:49:21 +00001875 static time_t
cristy208b1002011-08-07 18:51:50 +00001876 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001877
cristyc4f9f132010-03-04 18:50:01 +00001878 status=MagickTrue;
1879 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001880 if (cpu_throttle == 0)
1881 {
1882 char
1883 *limit;
1884
1885 /*
1886 Set CPU throttle in milleseconds.
1887 */
1888 cpu_throttle=MagickResourceInfinity;
1889 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1890 if (limit == (char *) NULL)
1891 limit=GetPolicyValue("throttle");
1892 if (limit != (char *) NULL)
1893 {
1894 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1895 limit=DestroyString(limit);
1896 }
1897 }
1898 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1899 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001900 if (time_limit == 0)
1901 {
cristy6ebe97c2010-07-03 01:17:28 +00001902 /*
1903 Set the exire time in seconds.
1904 */
cristy1ea34962010-07-01 19:49:21 +00001905 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001906 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001907 }
1908 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001909 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001910 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001911 assert(image->cache != (Cache) NULL);
1912 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001913 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +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 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001917 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001918 {
cristyceb55ee2010-11-06 16:05:49 +00001919 Image
1920 clone_image;
1921
1922 CacheInfo
1923 *clone_info;
1924
1925 /*
1926 Clone pixel cache.
1927 */
1928 clone_image=(*image);
1929 clone_image.semaphore=AllocateSemaphoreInfo();
1930 clone_image.reference_count=1;
1931 clone_image.cache=ClonePixelCache(cache_info);
1932 clone_info=(CacheInfo *) clone_image.cache;
1933 status=OpenPixelCache(&clone_image,IOMode,exception);
1934 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001935 {
cristy5a7fbfb2010-11-06 16:10:59 +00001936 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001937 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001938 if (status != MagickFalse)
1939 {
cristy979bf772011-08-08 00:04:15 +00001940 if (cache_info->mode == ReadMode)
1941 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001942 destroy=MagickTrue;
1943 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001944 }
1945 }
cristyceb55ee2010-11-06 16:05:49 +00001946 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001947 }
cristyceb55ee2010-11-06 16:05:49 +00001948 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001949 }
cristy4320e0e2009-09-10 15:00:08 +00001950 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001951 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001952 if (status != MagickFalse)
1953 {
1954 /*
1955 Ensure the image matches the pixel cache morphology.
1956 */
1957 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001958 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001959 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001960 {
1961 status=OpenPixelCache(image,IOMode,exception);
1962 cache_info=(CacheInfo *) image->cache;
1963 if (cache_info->type == DiskCache)
1964 (void) ClosePixelCacheOnDisk(cache_info);
1965 }
cristy3ed852e2009-09-05 21:47:34 +00001966 }
cristyf84a1932010-01-03 18:00:18 +00001967 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001968 if (status == MagickFalse)
1969 return((Cache) NULL);
1970 return(image->cache);
1971}
1972
1973/*
1974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1975% %
1976% %
1977% %
1978% G e t O n e A u t h e n t i c P i x e l %
1979% %
1980% %
1981% %
1982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1983%
1984% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1985% location. The image background color is returned if an error occurs.
1986%
1987% The format of the GetOneAuthenticPixel() method is:
1988%
cristybb503372010-05-27 20:51:26 +00001989% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00001990% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001991%
1992% A description of each parameter follows:
1993%
1994% o image: the image.
1995%
1996% o x,y: These values define the location of the pixel to return.
1997%
1998% o pixel: return a pixel at the specified (x,y) location.
1999%
2000% o exception: return any errors or warnings in this structure.
2001%
2002*/
cristyacbbb7c2010-06-30 18:56:48 +00002003MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002004 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002005{
2006 CacheInfo
2007 *cache_info;
2008
cristy4c08aed2011-07-01 19:47:50 +00002009 register Quantum
2010 *q;
cristy2036f5c2010-09-19 21:18:17 +00002011
cristy2ed42f62011-10-02 19:49:57 +00002012 register ssize_t
2013 i;
2014
cristy3ed852e2009-09-05 21:47:34 +00002015 assert(image != (Image *) NULL);
2016 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002017 assert(image->cache != (Cache) NULL);
2018 cache_info=(CacheInfo *) image->cache;
2019 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002020 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002021 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2022 (GetOneAuthenticPixelFromHandler) NULL)
2023 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2024 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002025 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2026 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002027 {
cristy9e0719b2011-12-29 03:45:45 +00002028 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2029 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2030 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2031 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2032 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002033 return(MagickFalse);
2034 }
2035 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2036 {
2037 PixelChannel
2038 channel;
2039
cristye2a912b2011-12-05 20:02:07 +00002040 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002041 pixel[channel]=q[i];
2042 }
cristy2036f5c2010-09-19 21:18:17 +00002043 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002044}
2045
2046/*
2047%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2048% %
2049% %
2050% %
2051+ 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 %
2052% %
2053% %
2054% %
2055%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2056%
2057% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2058% location. The image background color is returned if an error occurs.
2059%
2060% The format of the GetOneAuthenticPixelFromCache() method is:
2061%
2062% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002063% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002064% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002065%
2066% A description of each parameter follows:
2067%
2068% o image: the image.
2069%
2070% o x,y: These values define the location of the pixel to return.
2071%
2072% o pixel: return a pixel at the specified (x,y) location.
2073%
2074% o exception: return any errors or warnings in this structure.
2075%
2076*/
2077static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002078 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002079{
cristy098f78c2010-09-23 17:28:44 +00002080 CacheInfo
2081 *cache_info;
2082
2083 const int
2084 id = GetOpenMPThreadId();
2085
cristy4c08aed2011-07-01 19:47:50 +00002086 register Quantum
2087 *q;
cristy3ed852e2009-09-05 21:47:34 +00002088
cristy2ed42f62011-10-02 19:49:57 +00002089 register ssize_t
2090 i;
2091
cristy0158a4b2010-09-20 13:59:45 +00002092 assert(image != (const Image *) NULL);
2093 assert(image->signature == MagickSignature);
2094 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002095 cache_info=(CacheInfo *) image->cache;
2096 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002097 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002098 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002099 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2100 exception);
2101 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002102 {
cristy9e0719b2011-12-29 03:45:45 +00002103 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2104 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2105 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2106 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2107 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002108 return(MagickFalse);
2109 }
2110 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2111 {
2112 PixelChannel
2113 channel;
2114
cristye2a912b2011-12-05 20:02:07 +00002115 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002116 pixel[channel]=q[i];
2117 }
cristy3ed852e2009-09-05 21:47:34 +00002118 return(MagickTrue);
2119}
2120
2121/*
2122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2123% %
2124% %
2125% %
cristy3ed852e2009-09-05 21:47:34 +00002126% G e t O n e V i r t u a l P i x e l %
2127% %
2128% %
2129% %
2130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2131%
2132% GetOneVirtualPixel() returns a single virtual pixel at the specified
2133% (x,y) location. The image background color is returned if an error occurs.
2134% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2135%
2136% The format of the GetOneVirtualPixel() method is:
2137%
cristybb503372010-05-27 20:51:26 +00002138% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002139% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002140%
2141% A description of each parameter follows:
2142%
2143% o image: the image.
2144%
2145% o x,y: These values define the location of the pixel to return.
2146%
2147% o pixel: return a pixel at the specified (x,y) location.
2148%
2149% o exception: return any errors or warnings in this structure.
2150%
2151*/
2152MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002153 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002154{
cristy3ed852e2009-09-05 21:47:34 +00002155 CacheInfo
2156 *cache_info;
2157
cristy0158a4b2010-09-20 13:59:45 +00002158 const int
2159 id = GetOpenMPThreadId();
2160
cristy4c08aed2011-07-01 19:47:50 +00002161 const Quantum
2162 *p;
cristy2036f5c2010-09-19 21:18:17 +00002163
cristy2ed42f62011-10-02 19:49:57 +00002164 register ssize_t
2165 i;
2166
cristy3ed852e2009-09-05 21:47:34 +00002167 assert(image != (const Image *) NULL);
2168 assert(image->signature == MagickSignature);
2169 assert(image->cache != (Cache) NULL);
2170 cache_info=(CacheInfo *) image->cache;
2171 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002172 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002173 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2174 (GetOneVirtualPixelFromHandler) NULL)
2175 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2176 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002177 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002178 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002179 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002180 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002181 {
cristy9e0719b2011-12-29 03:45:45 +00002182 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2183 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2184 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2185 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2186 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002187 return(MagickFalse);
2188 }
2189 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2190 {
2191 PixelChannel
2192 channel;
2193
cristye2a912b2011-12-05 20:02:07 +00002194 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002195 pixel[channel]=p[i];
2196 }
cristy2036f5c2010-09-19 21:18:17 +00002197 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002198}
2199
2200/*
2201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2202% %
2203% %
2204% %
2205+ 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 %
2206% %
2207% %
2208% %
2209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2210%
2211% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2212% specified (x,y) location. The image background color is returned if an
2213% error occurs.
2214%
2215% The format of the GetOneVirtualPixelFromCache() method is:
2216%
2217% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002218% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002219% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002220%
2221% A description of each parameter follows:
2222%
2223% o image: the image.
2224%
2225% o virtual_pixel_method: the virtual pixel method.
2226%
2227% o x,y: These values define the location of the pixel to return.
2228%
2229% o pixel: return a pixel at the specified (x,y) location.
2230%
2231% o exception: return any errors or warnings in this structure.
2232%
2233*/
2234static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002235 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002236 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002237{
cristy0158a4b2010-09-20 13:59:45 +00002238 CacheInfo
2239 *cache_info;
2240
2241 const int
2242 id = GetOpenMPThreadId();
2243
cristy4c08aed2011-07-01 19:47:50 +00002244 const Quantum
2245 *p;
cristy3ed852e2009-09-05 21:47:34 +00002246
cristy2ed42f62011-10-02 19:49:57 +00002247 register ssize_t
2248 i;
2249
cristye7cc7cf2010-09-21 13:26:47 +00002250 assert(image != (const Image *) NULL);
2251 assert(image->signature == MagickSignature);
2252 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002253 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002254 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002255 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002256 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002257 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002258 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002259 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002260 {
cristy9e0719b2011-12-29 03:45:45 +00002261 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2262 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2263 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2264 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2265 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002266 return(MagickFalse);
2267 }
2268 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2269 {
2270 PixelChannel
2271 channel;
2272
cristye2a912b2011-12-05 20:02:07 +00002273 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002274 pixel[channel]=p[i];
2275 }
cristy3ed852e2009-09-05 21:47:34 +00002276 return(MagickTrue);
2277}
2278
2279/*
2280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281% %
2282% %
2283% %
cristy3aa93752011-12-18 15:54:24 +00002284% G e t O n e V i r t u a l P i x e l I n f o %
2285% %
2286% %
2287% %
2288%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2289%
2290% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2291% location. The image background color is returned if an error occurs. If
2292% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2293%
2294% The format of the GetOneVirtualPixelInfo() method is:
2295%
2296% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2297% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2298% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2299%
2300% A description of each parameter follows:
2301%
2302% o image: the image.
2303%
2304% o virtual_pixel_method: the virtual pixel method.
2305%
2306% o x,y: these values define the location of the pixel to return.
2307%
2308% o pixel: return a pixel at the specified (x,y) location.
2309%
2310% o exception: return any errors or warnings in this structure.
2311%
2312*/
2313MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2314 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2315 PixelInfo *pixel,ExceptionInfo *exception)
2316{
2317 CacheInfo
2318 *cache_info;
2319
2320 const int
2321 id = GetOpenMPThreadId();
2322
2323 register const Quantum
2324 *p;
2325
2326 assert(image != (const Image *) NULL);
2327 assert(image->signature == MagickSignature);
2328 assert(image->cache != (Cache) NULL);
2329 cache_info=(CacheInfo *) image->cache;
2330 assert(cache_info->signature == MagickSignature);
2331 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002332 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002333 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2334 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002335 if (p == (const Quantum *) NULL)
2336 return(MagickFalse);
2337 GetPixelInfoPixel(image,p,pixel);
2338 return(MagickTrue);
2339}
2340
2341/*
2342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2343% %
2344% %
2345% %
cristy3ed852e2009-09-05 21:47:34 +00002346+ G e t P i x e l C a c h e C o l o r s p a c e %
2347% %
2348% %
2349% %
2350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2351%
2352% GetPixelCacheColorspace() returns the class type of the pixel cache.
2353%
2354% The format of the GetPixelCacheColorspace() method is:
2355%
2356% Colorspace GetPixelCacheColorspace(Cache cache)
2357%
2358% A description of each parameter follows:
2359%
2360% o cache: the pixel cache.
2361%
2362*/
cristya6577ff2011-09-02 19:54:26 +00002363MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002364{
2365 CacheInfo
2366 *cache_info;
2367
2368 assert(cache != (Cache) NULL);
2369 cache_info=(CacheInfo *) cache;
2370 assert(cache_info->signature == MagickSignature);
2371 if (cache_info->debug != MagickFalse)
2372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2373 cache_info->filename);
2374 return(cache_info->colorspace);
2375}
2376
2377/*
2378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2379% %
2380% %
2381% %
2382+ G e t P i x e l C a c h e M e t h o d s %
2383% %
2384% %
2385% %
2386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2387%
2388% GetPixelCacheMethods() initializes the CacheMethods structure.
2389%
2390% The format of the GetPixelCacheMethods() method is:
2391%
2392% void GetPixelCacheMethods(CacheMethods *cache_methods)
2393%
2394% A description of each parameter follows:
2395%
2396% o cache_methods: Specifies a pointer to a CacheMethods structure.
2397%
2398*/
cristya6577ff2011-09-02 19:54:26 +00002399MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002400{
2401 assert(cache_methods != (CacheMethods *) NULL);
2402 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2403 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2404 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002405 cache_methods->get_virtual_metacontent_from_handler=
2406 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002407 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2408 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002409 cache_methods->get_authentic_metacontent_from_handler=
2410 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002411 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2412 cache_methods->get_one_authentic_pixel_from_handler=
2413 GetOneAuthenticPixelFromCache;
2414 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2415 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2416 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2417}
2418
2419/*
2420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2421% %
2422% %
2423% %
2424+ G e t P i x e l C a c h e N e x u s E x t e n t %
2425% %
2426% %
2427% %
2428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2429%
cristy4c08aed2011-07-01 19:47:50 +00002430% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2431% corresponding with the last call to SetPixelCacheNexusPixels() or
2432% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002433%
2434% The format of the GetPixelCacheNexusExtent() method is:
2435%
2436% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2437% NexusInfo *nexus_info)
2438%
2439% A description of each parameter follows:
2440%
2441% o nexus_info: the nexus info.
2442%
2443*/
cristya6577ff2011-09-02 19:54:26 +00002444MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002445 NexusInfo *nexus_info)
2446{
2447 CacheInfo
2448 *cache_info;
2449
2450 MagickSizeType
2451 extent;
2452
cristy9f027d12011-09-21 01:17:17 +00002453 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002454 cache_info=(CacheInfo *) cache;
2455 assert(cache_info->signature == MagickSignature);
2456 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2457 if (extent == 0)
2458 return((MagickSizeType) cache_info->columns*cache_info->rows);
2459 return(extent);
2460}
2461
2462/*
2463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2464% %
2465% %
2466% %
cristy4c08aed2011-07-01 19:47:50 +00002467+ 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 +00002468% %
2469% %
2470% %
2471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2472%
cristy4c08aed2011-07-01 19:47:50 +00002473% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2474% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002475%
cristy4c08aed2011-07-01 19:47:50 +00002476% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002477%
cristy4c08aed2011-07-01 19:47:50 +00002478% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002479% NexusInfo *nexus_info)
2480%
2481% A description of each parameter follows:
2482%
2483% o cache: the pixel cache.
2484%
cristy4c08aed2011-07-01 19:47:50 +00002485% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002486%
2487*/
cristya6577ff2011-09-02 19:54:26 +00002488MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002489 NexusInfo *nexus_info)
2490{
2491 CacheInfo
2492 *cache_info;
2493
cristy9f027d12011-09-21 01:17:17 +00002494 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002495 cache_info=(CacheInfo *) cache;
2496 assert(cache_info->signature == MagickSignature);
2497 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002498 return((void *) NULL);
2499 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002500}
2501
2502/*
2503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2504% %
2505% %
2506% %
2507+ G e t P i x e l C a c h e N e x u s P i x e l s %
2508% %
2509% %
2510% %
2511%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2512%
2513% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2514% cache nexus.
2515%
2516% The format of the GetPixelCacheNexusPixels() method is:
2517%
cristy4c08aed2011-07-01 19:47:50 +00002518% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002519% NexusInfo *nexus_info)
2520%
2521% A description of each parameter follows:
2522%
2523% o cache: the pixel cache.
2524%
2525% o nexus_info: the cache nexus to return the pixels.
2526%
2527*/
cristya6577ff2011-09-02 19:54:26 +00002528MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002529 NexusInfo *nexus_info)
2530{
2531 CacheInfo
2532 *cache_info;
2533
cristy9f027d12011-09-21 01:17:17 +00002534 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002535 cache_info=(CacheInfo *) cache;
2536 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002537 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002538 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002539 return(nexus_info->pixels);
2540}
2541
2542/*
2543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2544% %
2545% %
2546% %
cristy056ba772010-01-02 23:33:54 +00002547+ G e t P i x e l C a c h e P i x e l s %
2548% %
2549% %
2550% %
2551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2552%
2553% GetPixelCachePixels() returns the pixels associated with the specified image.
2554%
2555% The format of the GetPixelCachePixels() method is:
2556%
cristyf84a1932010-01-03 18:00:18 +00002557% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2558% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002559%
2560% A description of each parameter follows:
2561%
2562% o image: the image.
2563%
2564% o length: the pixel cache length.
2565%
cristyf84a1932010-01-03 18:00:18 +00002566% o exception: return any errors or warnings in this structure.
2567%
cristy056ba772010-01-02 23:33:54 +00002568*/
cristyd1dd6e42011-09-04 01:46:08 +00002569MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002570 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002571{
2572 CacheInfo
2573 *cache_info;
2574
2575 assert(image != (const Image *) NULL);
2576 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002577 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002578 assert(length != (MagickSizeType *) NULL);
2579 assert(exception != (ExceptionInfo *) NULL);
2580 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002581 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002582 assert(cache_info->signature == MagickSignature);
2583 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002584 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002585 return((void *) NULL);
2586 *length=cache_info->length;
2587 return((void *) cache_info->pixels);
2588}
2589
2590/*
2591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2592% %
2593% %
2594% %
cristyb32b90a2009-09-07 21:45:48 +00002595+ 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 +00002596% %
2597% %
2598% %
2599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2600%
2601% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2602%
2603% The format of the GetPixelCacheStorageClass() method is:
2604%
2605% ClassType GetPixelCacheStorageClass(Cache cache)
2606%
2607% A description of each parameter follows:
2608%
2609% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2610%
2611% o cache: the pixel cache.
2612%
2613*/
cristya6577ff2011-09-02 19:54:26 +00002614MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002615{
2616 CacheInfo
2617 *cache_info;
2618
2619 assert(cache != (Cache) NULL);
2620 cache_info=(CacheInfo *) cache;
2621 assert(cache_info->signature == MagickSignature);
2622 if (cache_info->debug != MagickFalse)
2623 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2624 cache_info->filename);
2625 return(cache_info->storage_class);
2626}
2627
2628/*
2629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630% %
2631% %
2632% %
cristyb32b90a2009-09-07 21:45:48 +00002633+ G e t P i x e l C a c h e T i l e S i z e %
2634% %
2635% %
2636% %
2637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2638%
2639% GetPixelCacheTileSize() returns the pixel cache tile size.
2640%
2641% The format of the GetPixelCacheTileSize() method is:
2642%
cristybb503372010-05-27 20:51:26 +00002643% void GetPixelCacheTileSize(const Image *image,size_t *width,
2644% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002645%
2646% A description of each parameter follows:
2647%
2648% o image: the image.
2649%
2650% o width: the optimize cache tile width in pixels.
2651%
2652% o height: the optimize cache tile height in pixels.
2653%
2654*/
cristya6577ff2011-09-02 19:54:26 +00002655MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002656 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002657{
cristy4c08aed2011-07-01 19:47:50 +00002658 CacheInfo
2659 *cache_info;
2660
cristyb32b90a2009-09-07 21:45:48 +00002661 assert(image != (Image *) NULL);
2662 assert(image->signature == MagickSignature);
2663 if (image->debug != MagickFalse)
2664 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002665 cache_info=(CacheInfo *) image->cache;
2666 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002667 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002668 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002669 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002670 *height=(*width);
2671}
2672
2673/*
2674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675% %
2676% %
2677% %
2678+ G e t P i x e l C a c h e T y p e %
2679% %
2680% %
2681% %
2682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2683%
2684% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2685%
2686% The format of the GetPixelCacheType() method is:
2687%
2688% CacheType GetPixelCacheType(const Image *image)
2689%
2690% A description of each parameter follows:
2691%
2692% o image: the image.
2693%
2694*/
cristya6577ff2011-09-02 19:54:26 +00002695MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002696{
2697 CacheInfo
2698 *cache_info;
2699
2700 assert(image != (Image *) NULL);
2701 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002702 assert(image->cache != (Cache) NULL);
2703 cache_info=(CacheInfo *) image->cache;
2704 assert(cache_info->signature == MagickSignature);
2705 return(cache_info->type);
2706}
2707
2708/*
2709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2710% %
2711% %
2712% %
cristy3ed852e2009-09-05 21:47:34 +00002713+ 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 %
2714% %
2715% %
2716% %
2717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2718%
2719% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2720% pixel cache. A virtual pixel is any pixel access that is outside the
2721% boundaries of the image cache.
2722%
2723% The format of the GetPixelCacheVirtualMethod() method is:
2724%
2725% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2726%
2727% A description of each parameter follows:
2728%
2729% o image: the image.
2730%
2731*/
cristyd1dd6e42011-09-04 01:46:08 +00002732MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002733{
2734 CacheInfo
2735 *cache_info;
2736
2737 assert(image != (Image *) NULL);
2738 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002739 assert(image->cache != (Cache) NULL);
2740 cache_info=(CacheInfo *) image->cache;
2741 assert(cache_info->signature == MagickSignature);
2742 return(cache_info->virtual_pixel_method);
2743}
2744
2745/*
2746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2747% %
2748% %
2749% %
cristy4c08aed2011-07-01 19:47:50 +00002750+ 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 +00002751% %
2752% %
2753% %
2754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2755%
cristy4c08aed2011-07-01 19:47:50 +00002756% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2757% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002758%
cristy4c08aed2011-07-01 19:47:50 +00002759% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002760%
cristy4c08aed2011-07-01 19:47:50 +00002761% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002762%
2763% A description of each parameter follows:
2764%
2765% o image: the image.
2766%
2767*/
cristy4c08aed2011-07-01 19:47:50 +00002768static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002769{
2770 CacheInfo
2771 *cache_info;
2772
cristy5c9e6f22010-09-17 17:31:01 +00002773 const int
2774 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002775
cristy4c08aed2011-07-01 19:47:50 +00002776 const void
2777 *metacontent;
2778
cristye7cc7cf2010-09-21 13:26:47 +00002779 assert(image != (const Image *) NULL);
2780 assert(image->signature == MagickSignature);
2781 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002782 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002783 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002784 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002785 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2786 cache_info->nexus_info[id]);
2787 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002788}
2789
2790/*
2791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2792% %
2793% %
2794% %
cristy4c08aed2011-07-01 19:47:50 +00002795+ 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 +00002796% %
2797% %
2798% %
2799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2800%
cristy4c08aed2011-07-01 19:47:50 +00002801% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2802% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002803%
cristy4c08aed2011-07-01 19:47:50 +00002804% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002805%
cristy4c08aed2011-07-01 19:47:50 +00002806% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002807% NexusInfo *nexus_info)
2808%
2809% A description of each parameter follows:
2810%
2811% o cache: the pixel cache.
2812%
cristy4c08aed2011-07-01 19:47:50 +00002813% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002814%
2815*/
cristya6577ff2011-09-02 19:54:26 +00002816MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002817 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002818{
2819 CacheInfo
2820 *cache_info;
2821
cristye7cc7cf2010-09-21 13:26:47 +00002822 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002823 cache_info=(CacheInfo *) cache;
2824 assert(cache_info->signature == MagickSignature);
2825 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002826 return((void *) NULL);
2827 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002828}
2829
2830/*
2831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2832% %
2833% %
2834% %
cristy4c08aed2011-07-01 19:47:50 +00002835% 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 +00002836% %
2837% %
2838% %
2839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2840%
cristy4c08aed2011-07-01 19:47:50 +00002841% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2842% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2843% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002844%
cristy4c08aed2011-07-01 19:47:50 +00002845% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002846%
cristy4c08aed2011-07-01 19:47:50 +00002847% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002848%
2849% A description of each parameter follows:
2850%
2851% o image: the image.
2852%
2853*/
cristy4c08aed2011-07-01 19:47:50 +00002854MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002855{
2856 CacheInfo
2857 *cache_info;
2858
cristy2036f5c2010-09-19 21:18:17 +00002859 const int
2860 id = GetOpenMPThreadId();
2861
cristy4c08aed2011-07-01 19:47:50 +00002862 const void
2863 *metacontent;
2864
cristy3ed852e2009-09-05 21:47:34 +00002865 assert(image != (const Image *) NULL);
2866 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002867 assert(image->cache != (Cache) NULL);
2868 cache_info=(CacheInfo *) image->cache;
2869 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002870 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2871 if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
2872 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002873 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002874 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2875 cache_info->nexus_info[id]);
2876 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002877}
2878
2879/*
2880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2881% %
2882% %
2883% %
2884+ 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 %
2885% %
2886% %
2887% %
2888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2889%
2890% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2891% pixel cache as defined by the geometry parameters. A pointer to the pixels
2892% is returned if the pixels are transferred, otherwise a NULL is returned.
2893%
2894% The format of the GetVirtualPixelsFromNexus() method is:
2895%
cristy4c08aed2011-07-01 19:47:50 +00002896% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002897% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002898% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2899% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002900%
2901% A description of each parameter follows:
2902%
2903% o image: the image.
2904%
2905% o virtual_pixel_method: the virtual pixel method.
2906%
2907% o x,y,columns,rows: These values define the perimeter of a region of
2908% pixels.
2909%
2910% o nexus_info: the cache nexus to acquire.
2911%
2912% o exception: return any errors or warnings in this structure.
2913%
2914*/
2915
cristybb503372010-05-27 20:51:26 +00002916static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002917 DitherMatrix[64] =
2918 {
2919 0, 48, 12, 60, 3, 51, 15, 63,
2920 32, 16, 44, 28, 35, 19, 47, 31,
2921 8, 56, 4, 52, 11, 59, 7, 55,
2922 40, 24, 36, 20, 43, 27, 39, 23,
2923 2, 50, 14, 62, 1, 49, 13, 61,
2924 34, 18, 46, 30, 33, 17, 45, 29,
2925 10, 58, 6, 54, 9, 57, 5, 53,
2926 42, 26, 38, 22, 41, 25, 37, 21
2927 };
2928
cristybb503372010-05-27 20:51:26 +00002929static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002930{
cristybb503372010-05-27 20:51:26 +00002931 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002932 index;
2933
2934 index=x+DitherMatrix[x & 0x07]-32L;
2935 if (index < 0L)
2936 return(0L);
cristybb503372010-05-27 20:51:26 +00002937 if (index >= (ssize_t) columns)
2938 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002939 return(index);
2940}
2941
cristybb503372010-05-27 20:51:26 +00002942static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002943{
cristybb503372010-05-27 20:51:26 +00002944 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002945 index;
2946
2947 index=y+DitherMatrix[y & 0x07]-32L;
2948 if (index < 0L)
2949 return(0L);
cristybb503372010-05-27 20:51:26 +00002950 if (index >= (ssize_t) rows)
2951 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002952 return(index);
2953}
2954
cristybb503372010-05-27 20:51:26 +00002955static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002956{
2957 if (x < 0L)
2958 return(0L);
cristybb503372010-05-27 20:51:26 +00002959 if (x >= (ssize_t) columns)
2960 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002961 return(x);
2962}
2963
cristybb503372010-05-27 20:51:26 +00002964static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002965{
2966 if (y < 0L)
2967 return(0L);
cristybb503372010-05-27 20:51:26 +00002968 if (y >= (ssize_t) rows)
2969 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002970 return(y);
2971}
2972
cristybb503372010-05-27 20:51:26 +00002973static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002974{
cristybb503372010-05-27 20:51:26 +00002975 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002976}
2977
cristybb503372010-05-27 20:51:26 +00002978static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002979{
cristybb503372010-05-27 20:51:26 +00002980 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002981}
2982
cristybb503372010-05-27 20:51:26 +00002983static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2984 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002985{
2986 MagickModulo
2987 modulo;
2988
cristy6162bb42011-07-18 11:34:09 +00002989 /*
2990 Compute the remainder of dividing offset by extent. It returns not only
2991 the quotient (tile the offset falls in) but also the positive remainer
2992 within that tile such that 0 <= remainder < extent. This method is
2993 essentially a ldiv() using a floored modulo division rather than the
2994 normal default truncated modulo division.
2995 */
cristybb503372010-05-27 20:51:26 +00002996 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002997 if (offset < 0L)
2998 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00002999 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003000 return(modulo);
3001}
3002
cristya6577ff2011-09-02 19:54:26 +00003003MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003004 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3005 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003006 ExceptionInfo *exception)
3007{
3008 CacheInfo
3009 *cache_info;
3010
3011 MagickOffsetType
3012 offset;
3013
3014 MagickSizeType
3015 length,
3016 number_pixels;
3017
3018 NexusInfo
3019 **virtual_nexus;
3020
cristy4c08aed2011-07-01 19:47:50 +00003021 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003022 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003023 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003024
3025 RectangleInfo
3026 region;
3027
cristy4c08aed2011-07-01 19:47:50 +00003028 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003029 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003030
cristy4c08aed2011-07-01 19:47:50 +00003031 register const void
3032 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003033
cristy4c08aed2011-07-01 19:47:50 +00003034 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003035 *restrict q;
3036
cristybb503372010-05-27 20:51:26 +00003037 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003038 i,
3039 u;
cristy3ed852e2009-09-05 21:47:34 +00003040
cristy4c08aed2011-07-01 19:47:50 +00003041 register unsigned char
3042 *restrict s;
3043
cristy105ba3c2011-07-18 02:28:38 +00003044 ssize_t
3045 v;
3046
cristy4c08aed2011-07-01 19:47:50 +00003047 void
cristy105ba3c2011-07-18 02:28:38 +00003048 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003049
cristy3ed852e2009-09-05 21:47:34 +00003050 /*
3051 Acquire pixels.
3052 */
cristye7cc7cf2010-09-21 13:26:47 +00003053 assert(image != (const Image *) NULL);
3054 assert(image->signature == MagickSignature);
3055 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003056 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003057 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003058 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003059 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003060 region.x=x;
3061 region.y=y;
3062 region.width=columns;
3063 region.height=rows;
3064 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003065 if (pixels == (Quantum *) NULL)
3066 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003067 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003068 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3069 nexus_info->region.x;
3070 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3071 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003072 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3073 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003074 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3075 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003076 {
3077 MagickBooleanType
3078 status;
3079
3080 /*
3081 Pixel request is inside cache extents.
3082 */
cristy4c08aed2011-07-01 19:47:50 +00003083 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003084 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003085 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3086 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003087 return((const Quantum *) NULL);
3088 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003089 {
cristy4c08aed2011-07-01 19:47:50 +00003090 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003091 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003092 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003093 }
cristyacd2ed22011-08-30 01:44:23 +00003094 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003095 }
3096 /*
3097 Pixel request is outside cache extents.
3098 */
cristy4c08aed2011-07-01 19:47:50 +00003099 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003100 virtual_nexus=AcquirePixelCacheNexus(1);
3101 if (virtual_nexus == (NexusInfo **) NULL)
3102 {
cristy4c08aed2011-07-01 19:47:50 +00003103 if (virtual_nexus != (NexusInfo **) NULL)
3104 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003105 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003106 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003107 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003108 }
cristy105ba3c2011-07-18 02:28:38 +00003109 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3110 sizeof(*virtual_pixel));
3111 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003112 switch (virtual_pixel_method)
3113 {
cristy4c08aed2011-07-01 19:47:50 +00003114 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003115 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003116 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003117 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003118 case MaskVirtualPixelMethod:
3119 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003120 case EdgeVirtualPixelMethod:
3121 case CheckerTileVirtualPixelMethod:
3122 case HorizontalTileVirtualPixelMethod:
3123 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003124 {
cristy4c08aed2011-07-01 19:47:50 +00003125 if (cache_info->metacontent_extent != 0)
3126 {
cristy6162bb42011-07-18 11:34:09 +00003127 /*
3128 Acquire a metacontent buffer.
3129 */
cristya64b85d2011-09-14 01:02:31 +00003130 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003131 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003132 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003133 {
cristy4c08aed2011-07-01 19:47:50 +00003134 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3135 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003136 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003137 return((const Quantum *) NULL);
3138 }
cristy105ba3c2011-07-18 02:28:38 +00003139 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003140 cache_info->metacontent_extent);
3141 }
3142 switch (virtual_pixel_method)
3143 {
3144 case BlackVirtualPixelMethod:
3145 {
cristy30301712011-07-18 15:06:51 +00003146 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3147 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003148 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3149 break;
3150 }
3151 case GrayVirtualPixelMethod:
3152 {
cristy30301712011-07-18 15:06:51 +00003153 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003154 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3155 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003156 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3157 break;
3158 }
3159 case TransparentVirtualPixelMethod:
3160 {
cristy30301712011-07-18 15:06:51 +00003161 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3162 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003163 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3164 break;
3165 }
3166 case MaskVirtualPixelMethod:
3167 case WhiteVirtualPixelMethod:
3168 {
cristy30301712011-07-18 15:06:51 +00003169 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3170 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003171 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3172 break;
3173 }
3174 default:
3175 {
cristy9e0719b2011-12-29 03:45:45 +00003176 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3177 virtual_pixel);
3178 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3179 virtual_pixel);
3180 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3181 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003182 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3183 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003184 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3185 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003186 break;
3187 }
3188 }
cristy3ed852e2009-09-05 21:47:34 +00003189 break;
3190 }
3191 default:
cristy3ed852e2009-09-05 21:47:34 +00003192 break;
cristy3ed852e2009-09-05 21:47:34 +00003193 }
cristybb503372010-05-27 20:51:26 +00003194 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003195 {
cristybb503372010-05-27 20:51:26 +00003196 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003197 {
3198 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003199 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003200 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3201 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003202 {
3203 MagickModulo
3204 x_modulo,
3205 y_modulo;
3206
3207 /*
3208 Transfer a single pixel.
3209 */
3210 length=(MagickSizeType) 1;
3211 switch (virtual_pixel_method)
3212 {
cristy3ed852e2009-09-05 21:47:34 +00003213 default:
3214 {
3215 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003216 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003217 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003218 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003219 break;
3220 }
3221 case RandomVirtualPixelMethod:
3222 {
3223 if (cache_info->random_info == (RandomInfo *) NULL)
3224 cache_info->random_info=AcquireRandomInfo();
3225 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003226 RandomX(cache_info->random_info,cache_info->columns),
3227 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003228 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003229 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003230 break;
3231 }
3232 case DitherVirtualPixelMethod:
3233 {
3234 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003235 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003236 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003237 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003238 break;
3239 }
3240 case TileVirtualPixelMethod:
3241 {
3242 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3243 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3244 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003245 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003246 exception);
cristy4c08aed2011-07-01 19:47:50 +00003247 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003248 break;
3249 }
3250 case MirrorVirtualPixelMethod:
3251 {
3252 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3253 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003254 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003255 x_modulo.remainder-1L;
3256 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3257 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003258 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003259 y_modulo.remainder-1L;
3260 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003261 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003262 exception);
cristy4c08aed2011-07-01 19:47:50 +00003263 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003264 break;
3265 }
3266 case HorizontalTileEdgeVirtualPixelMethod:
3267 {
3268 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3269 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003270 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003271 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003272 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003273 break;
3274 }
3275 case VerticalTileEdgeVirtualPixelMethod:
3276 {
3277 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3278 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003279 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003280 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003281 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3282 break;
3283 }
3284 case BackgroundVirtualPixelMethod:
3285 case BlackVirtualPixelMethod:
3286 case GrayVirtualPixelMethod:
3287 case TransparentVirtualPixelMethod:
3288 case MaskVirtualPixelMethod:
3289 case WhiteVirtualPixelMethod:
3290 {
3291 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003292 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003293 break;
3294 }
3295 case EdgeVirtualPixelMethod:
3296 case CheckerTileVirtualPixelMethod:
3297 {
3298 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3299 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3300 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3301 {
3302 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003303 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003304 break;
3305 }
3306 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3307 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3308 exception);
3309 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3310 break;
3311 }
3312 case HorizontalTileVirtualPixelMethod:
3313 {
3314 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3315 {
3316 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003317 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003318 break;
3319 }
3320 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3321 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3322 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3323 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3324 exception);
3325 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3326 break;
3327 }
3328 case VerticalTileVirtualPixelMethod:
3329 {
3330 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3331 {
3332 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003333 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003334 break;
3335 }
3336 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3337 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3338 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3339 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3340 exception);
3341 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003342 break;
3343 }
3344 }
cristy4c08aed2011-07-01 19:47:50 +00003345 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003346 break;
cristyed231572011-07-14 02:18:59 +00003347 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003348 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003349 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003350 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003351 {
3352 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3353 s+=cache_info->metacontent_extent;
3354 }
cristy3ed852e2009-09-05 21:47:34 +00003355 continue;
3356 }
3357 /*
3358 Transfer a run of pixels.
3359 */
cristy4c08aed2011-07-01 19:47:50 +00003360 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3361 length,1UL,*virtual_nexus,exception);
3362 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003363 break;
cristy4c08aed2011-07-01 19:47:50 +00003364 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003365 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3366 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003367 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003368 {
cristy4c08aed2011-07-01 19:47:50 +00003369 (void) memcpy(s,r,(size_t) length);
3370 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003371 }
3372 }
3373 }
cristy4c08aed2011-07-01 19:47:50 +00003374 /*
3375 Free resources.
3376 */
cristy105ba3c2011-07-18 02:28:38 +00003377 if (virtual_metacontent != (void *) NULL)
3378 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003379 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3380 return(pixels);
3381}
3382
3383/*
3384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3385% %
3386% %
3387% %
3388+ G e t V i r t u a l P i x e l C a c h e %
3389% %
3390% %
3391% %
3392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3393%
3394% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3395% cache as defined by the geometry parameters. A pointer to the pixels
3396% is returned if the pixels are transferred, otherwise a NULL is returned.
3397%
3398% The format of the GetVirtualPixelCache() method is:
3399%
cristy4c08aed2011-07-01 19:47:50 +00003400% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003401% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3402% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003403% ExceptionInfo *exception)
3404%
3405% A description of each parameter follows:
3406%
3407% o image: the image.
3408%
3409% o virtual_pixel_method: the virtual pixel method.
3410%
3411% o x,y,columns,rows: These values define the perimeter of a region of
3412% pixels.
3413%
3414% o exception: return any errors or warnings in this structure.
3415%
3416*/
cristy4c08aed2011-07-01 19:47:50 +00003417static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003418 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3419 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003420{
3421 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003422 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003423
cristy5c9e6f22010-09-17 17:31:01 +00003424 const int
3425 id = GetOpenMPThreadId();
3426
cristy4c08aed2011-07-01 19:47:50 +00003427 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003428 *p;
cristy4c08aed2011-07-01 19:47:50 +00003429
cristye7cc7cf2010-09-21 13:26:47 +00003430 assert(image != (const Image *) NULL);
3431 assert(image->signature == MagickSignature);
3432 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003433 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003434 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003435 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003436 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003437 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003438 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003439}
3440
3441/*
3442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3443% %
3444% %
3445% %
3446% G e t V i r t u a l P i x e l Q u e u e %
3447% %
3448% %
3449% %
3450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3451%
cristy4c08aed2011-07-01 19:47:50 +00003452% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3453% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003454%
3455% The format of the GetVirtualPixelQueue() method is:
3456%
cristy4c08aed2011-07-01 19:47:50 +00003457% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003458%
3459% A description of each parameter follows:
3460%
3461% o image: the image.
3462%
3463*/
cristy4c08aed2011-07-01 19:47:50 +00003464MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003465{
3466 CacheInfo
3467 *cache_info;
3468
cristy2036f5c2010-09-19 21:18:17 +00003469 const int
3470 id = GetOpenMPThreadId();
3471
cristy3ed852e2009-09-05 21:47:34 +00003472 assert(image != (const Image *) NULL);
3473 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003474 assert(image->cache != (Cache) NULL);
3475 cache_info=(CacheInfo *) image->cache;
3476 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003477 if (cache_info->methods.get_virtual_pixels_handler !=
3478 (GetVirtualPixelsHandler) NULL)
3479 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003480 assert(id < (int) cache_info->number_threads);
3481 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003482}
3483
3484/*
3485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3486% %
3487% %
3488% %
3489% G e t V i r t u a l P i x e l s %
3490% %
3491% %
3492% %
3493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3494%
3495% GetVirtualPixels() returns an immutable pixel region. If the
3496% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003497% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003498% copy of the pixels or it may point to the original pixels in memory.
3499% Performance is maximized if the selected region is part of one row, or one
3500% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003501% (without a copy) if the image is in memory, or in a memory-mapped file. The
3502% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003503%
3504% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003505% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3506% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3507% access the meta-content (of type void) corresponding to the the
3508% region.
cristy3ed852e2009-09-05 21:47:34 +00003509%
3510% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3511%
3512% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3513% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3514% GetCacheViewAuthenticPixels() instead.
3515%
3516% The format of the GetVirtualPixels() method is:
3517%
cristy4c08aed2011-07-01 19:47:50 +00003518% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003519% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003520% ExceptionInfo *exception)
3521%
3522% A description of each parameter follows:
3523%
3524% o image: the image.
3525%
3526% o x,y,columns,rows: These values define the perimeter of a region of
3527% pixels.
3528%
3529% o exception: return any errors or warnings in this structure.
3530%
3531*/
cristy4c08aed2011-07-01 19:47:50 +00003532MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003533 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3534 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003535{
3536 CacheInfo
3537 *cache_info;
3538
cristy2036f5c2010-09-19 21:18:17 +00003539 const int
3540 id = GetOpenMPThreadId();
3541
cristy4c08aed2011-07-01 19:47:50 +00003542 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003543 *p;
cristy4c08aed2011-07-01 19:47:50 +00003544
cristy3ed852e2009-09-05 21:47:34 +00003545 assert(image != (const Image *) NULL);
3546 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003547 assert(image->cache != (Cache) NULL);
3548 cache_info=(CacheInfo *) image->cache;
3549 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003550 if (cache_info->methods.get_virtual_pixel_handler !=
3551 (GetVirtualPixelHandler) NULL)
3552 return(cache_info->methods.get_virtual_pixel_handler(image,
3553 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003554 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003555 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003556 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003557 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003558}
3559
3560/*
3561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562% %
3563% %
3564% %
3565+ 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 %
3566% %
3567% %
3568% %
3569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3570%
cristy4c08aed2011-07-01 19:47:50 +00003571% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3572% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003573%
3574% The format of the GetVirtualPixelsCache() method is:
3575%
cristy4c08aed2011-07-01 19:47:50 +00003576% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003577%
3578% A description of each parameter follows:
3579%
3580% o image: the image.
3581%
3582*/
cristy4c08aed2011-07-01 19:47:50 +00003583static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003584{
3585 CacheInfo
3586 *cache_info;
3587
cristy5c9e6f22010-09-17 17:31:01 +00003588 const int
3589 id = GetOpenMPThreadId();
3590
cristye7cc7cf2010-09-21 13:26:47 +00003591 assert(image != (const Image *) NULL);
3592 assert(image->signature == MagickSignature);
3593 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003594 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003595 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003596 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003597 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003598}
3599
3600/*
3601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3602% %
3603% %
3604% %
3605+ G e t V i r t u a l P i x e l s N e x u s %
3606% %
3607% %
3608% %
3609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3610%
3611% GetVirtualPixelsNexus() returns the pixels associated with the specified
3612% cache nexus.
3613%
3614% The format of the GetVirtualPixelsNexus() method is:
3615%
cristy4c08aed2011-07-01 19:47:50 +00003616% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003617% NexusInfo *nexus_info)
3618%
3619% A description of each parameter follows:
3620%
3621% o cache: the pixel cache.
3622%
3623% o nexus_info: the cache nexus to return the colormap pixels.
3624%
3625*/
cristya6577ff2011-09-02 19:54:26 +00003626MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003627 NexusInfo *nexus_info)
3628{
3629 CacheInfo
3630 *cache_info;
3631
cristye7cc7cf2010-09-21 13:26:47 +00003632 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003633 cache_info=(CacheInfo *) cache;
3634 assert(cache_info->signature == MagickSignature);
3635 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003636 return((Quantum *) NULL);
3637 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003638}
3639
3640/*
3641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3642% %
3643% %
3644% %
cristy3ed852e2009-09-05 21:47:34 +00003645+ O p e n P i x e l C a c h e %
3646% %
3647% %
3648% %
3649%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3650%
3651% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3652% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003653% metacontent, and memory mapping the cache if it is disk based. The cache
3654% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003655%
3656% The format of the OpenPixelCache() method is:
3657%
3658% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3659% ExceptionInfo *exception)
3660%
3661% A description of each parameter follows:
3662%
3663% o image: the image.
3664%
3665% o mode: ReadMode, WriteMode, or IOMode.
3666%
3667% o exception: return any errors or warnings in this structure.
3668%
3669*/
3670
cristyd43a46b2010-01-21 02:13:41 +00003671static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003672{
3673 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003674 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003675 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003676 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003677 {
3678 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003679 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003680 cache_info->length);
3681 }
3682}
3683
3684static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3685{
3686 CacheInfo
3687 *cache_info;
3688
3689 MagickOffsetType
3690 count,
3691 extent,
3692 offset;
3693
3694 cache_info=(CacheInfo *) image->cache;
3695 if (image->debug != MagickFalse)
3696 {
3697 char
3698 format[MaxTextExtent],
3699 message[MaxTextExtent];
3700
cristyb9080c92009-12-01 20:13:26 +00003701 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003702 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003703 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003704 cache_info->cache_filename,cache_info->file,format);
3705 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3706 }
3707 if (length != (MagickSizeType) ((MagickOffsetType) length))
3708 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003709 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003710 if (extent < 0)
3711 return(MagickFalse);
3712 if ((MagickSizeType) extent >= length)
3713 return(MagickTrue);
3714 offset=(MagickOffsetType) length-1;
3715 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3716 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3717}
3718
3719static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3720 ExceptionInfo *exception)
3721{
cristy3ed852e2009-09-05 21:47:34 +00003722 CacheInfo
3723 *cache_info,
3724 source_info;
3725
cristyf3a6a9d2010-11-07 21:02:56 +00003726 char
3727 format[MaxTextExtent],
3728 message[MaxTextExtent];
3729
cristy4c08aed2011-07-01 19:47:50 +00003730 MagickBooleanType
3731 status;
3732
cristy3ed852e2009-09-05 21:47:34 +00003733 MagickSizeType
3734 length,
3735 number_pixels;
3736
cristy3ed852e2009-09-05 21:47:34 +00003737 size_t
cristye076a6e2010-08-15 19:59:43 +00003738 columns,
cristy3ed852e2009-09-05 21:47:34 +00003739 packet_size;
3740
cristye7cc7cf2010-09-21 13:26:47 +00003741 assert(image != (const Image *) NULL);
3742 assert(image->signature == MagickSignature);
3743 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003744 if (image->debug != MagickFalse)
3745 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3746 if ((image->columns == 0) || (image->rows == 0))
3747 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3748 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003749 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003750 source_info=(*cache_info);
3751 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003752 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003753 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003754 cache_info->storage_class=image->storage_class;
3755 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003756 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003757 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003758 cache_info->rows=image->rows;
3759 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003760 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003761 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003762 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3763 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003764 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003765 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003766 if (image->ping != MagickFalse)
3767 {
cristy73724512010-04-12 14:43:14 +00003768 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003769 cache_info->pixels=(Quantum *) NULL;
3770 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003771 cache_info->length=0;
3772 return(MagickTrue);
3773 }
cristy3ed852e2009-09-05 21:47:34 +00003774 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003775 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003776 if (image->metacontent_extent != 0)
3777 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003778 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003779 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003780 if (cache_info->columns != columns)
3781 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3782 image->filename);
3783 cache_info->length=length;
3784 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003785 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003786 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003787 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3788 {
3789 status=AcquireMagickResource(MemoryResource,cache_info->length);
3790 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3791 (cache_info->type == MemoryCache))
3792 {
cristyd43a46b2010-01-21 02:13:41 +00003793 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003794 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003795 cache_info->pixels=source_info.pixels;
3796 else
3797 {
3798 /*
3799 Create memory pixel cache.
3800 */
cristy4c08aed2011-07-01 19:47:50 +00003801 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003802 if (image->debug != MagickFalse)
3803 {
cristy32cacff2011-12-31 03:36:27 +00003804 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003805 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003806 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3807 cache_info->filename,cache_info->mapped != MagickFalse ?
3808 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003809 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003810 format);
cristy3ed852e2009-09-05 21:47:34 +00003811 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3812 message);
3813 }
cristy3ed852e2009-09-05 21:47:34 +00003814 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003815 cache_info->metacontent=(void *) NULL;
3816 if (cache_info->metacontent_extent != 0)
3817 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003818 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003819 if ((source_info.storage_class != UndefinedClass) &&
3820 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003821 {
cristy4c08aed2011-07-01 19:47:50 +00003822 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003823 exception);
3824 RelinquishPixelCachePixels(&source_info);
3825 }
cristy4c08aed2011-07-01 19:47:50 +00003826 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003827 }
3828 }
3829 RelinquishMagickResource(MemoryResource,cache_info->length);
3830 }
3831 /*
3832 Create pixel cache on disk.
3833 */
3834 status=AcquireMagickResource(DiskResource,cache_info->length);
3835 if (status == MagickFalse)
3836 {
3837 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003838 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003839 return(MagickFalse);
3840 }
cristy413f1302012-01-01 17:48:27 +00003841 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3842 {
3843 (void) ClosePixelCacheOnDisk(cache_info);
3844 *cache_info->cache_filename='\0';
3845 }
cristy3ed852e2009-09-05 21:47:34 +00003846 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3847 {
3848 RelinquishMagickResource(DiskResource,cache_info->length);
3849 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3850 image->filename);
3851 return(MagickFalse);
3852 }
3853 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3854 cache_info->length);
3855 if (status == MagickFalse)
3856 {
3857 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3858 image->filename);
3859 return(MagickFalse);
3860 }
cristyed231572011-07-14 02:18:59 +00003861 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003862 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003863 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003864 cache_info->type=DiskCache;
3865 else
3866 {
3867 status=AcquireMagickResource(MapResource,cache_info->length);
3868 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3869 (cache_info->type != MemoryCache))
3870 cache_info->type=DiskCache;
3871 else
3872 {
cristy4c08aed2011-07-01 19:47:50 +00003873 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003874 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003875 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003876 {
cristy3ed852e2009-09-05 21:47:34 +00003877 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003878 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003879 }
3880 else
3881 {
3882 /*
3883 Create file-backed memory-mapped pixel cache.
3884 */
cristy4c08aed2011-07-01 19:47:50 +00003885 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003886 (void) ClosePixelCacheOnDisk(cache_info);
3887 cache_info->type=MapCache;
3888 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003889 cache_info->metacontent=(void *) NULL;
3890 if (cache_info->metacontent_extent != 0)
3891 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003892 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003893 if ((source_info.storage_class != UndefinedClass) &&
3894 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003895 {
3896 status=ClonePixelCachePixels(cache_info,&source_info,
3897 exception);
3898 RelinquishPixelCachePixels(&source_info);
3899 }
3900 if (image->debug != MagickFalse)
3901 {
cristy413f1302012-01-01 17:48:27 +00003902 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003903 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003904 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003905 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003906 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003907 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003908 format);
cristy3ed852e2009-09-05 21:47:34 +00003909 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3910 message);
3911 }
cristy4c08aed2011-07-01 19:47:50 +00003912 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003913 }
3914 }
3915 RelinquishMagickResource(MapResource,cache_info->length);
3916 }
cristy4c08aed2011-07-01 19:47:50 +00003917 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003918 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003919 {
3920 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3921 RelinquishPixelCachePixels(&source_info);
3922 }
3923 if (image->debug != MagickFalse)
3924 {
cristyb9080c92009-12-01 20:13:26 +00003925 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003926 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003927 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003928 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003929 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003930 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003931 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3932 }
cristy4c08aed2011-07-01 19:47:50 +00003933 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003934}
3935
3936/*
3937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3938% %
3939% %
3940% %
3941+ P e r s i s t P i x e l C a c h e %
3942% %
3943% %
3944% %
3945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3946%
3947% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3948% persistent pixel cache is one that resides on disk and is not destroyed
3949% when the program exits.
3950%
3951% The format of the PersistPixelCache() method is:
3952%
3953% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3954% const MagickBooleanType attach,MagickOffsetType *offset,
3955% ExceptionInfo *exception)
3956%
3957% A description of each parameter follows:
3958%
3959% o image: the image.
3960%
3961% o filename: the persistent pixel cache filename.
3962%
cristyf3a6a9d2010-11-07 21:02:56 +00003963% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003964%
cristy3ed852e2009-09-05 21:47:34 +00003965% o initialize: A value other than zero initializes the persistent pixel
3966% cache.
3967%
3968% o offset: the offset in the persistent cache to store pixels.
3969%
3970% o exception: return any errors or warnings in this structure.
3971%
3972*/
3973MagickExport MagickBooleanType PersistPixelCache(Image *image,
3974 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3975 ExceptionInfo *exception)
3976{
3977 CacheInfo
3978 *cache_info,
3979 *clone_info;
3980
3981 Image
3982 clone_image;
3983
cristy3ed852e2009-09-05 21:47:34 +00003984 MagickBooleanType
3985 status;
3986
cristye076a6e2010-08-15 19:59:43 +00003987 ssize_t
3988 page_size;
3989
cristy3ed852e2009-09-05 21:47:34 +00003990 assert(image != (Image *) NULL);
3991 assert(image->signature == MagickSignature);
3992 if (image->debug != MagickFalse)
3993 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3994 assert(image->cache != (void *) NULL);
3995 assert(filename != (const char *) NULL);
3996 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00003997 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00003998 cache_info=(CacheInfo *) image->cache;
3999 assert(cache_info->signature == MagickSignature);
4000 if (attach != MagickFalse)
4001 {
4002 /*
cristy01b7eb02009-09-10 23:10:14 +00004003 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004004 */
4005 if (image->debug != MagickFalse)
4006 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004007 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004008 (void) CopyMagickString(cache_info->cache_filename,filename,
4009 MaxTextExtent);
4010 cache_info->type=DiskCache;
4011 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004012 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004013 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004014 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004015 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004016 }
cristy01b7eb02009-09-10 23:10:14 +00004017 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4018 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004019 {
cristyf84a1932010-01-03 18:00:18 +00004020 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004021 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004022 (cache_info->reference_count == 1))
4023 {
4024 int
4025 status;
4026
4027 /*
cristy01b7eb02009-09-10 23:10:14 +00004028 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004029 */
cristy320684d2011-09-23 14:55:47 +00004030 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004031 if (status == 0)
4032 {
4033 (void) CopyMagickString(cache_info->cache_filename,filename,
4034 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004035 *offset+=cache_info->length+page_size-(cache_info->length %
4036 page_size);
cristyf84a1932010-01-03 18:00:18 +00004037 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004038 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004039 if (image->debug != MagickFalse)
4040 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4041 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004042 return(MagickTrue);
4043 }
4044 }
cristyf84a1932010-01-03 18:00:18 +00004045 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004046 }
4047 /*
cristy01b7eb02009-09-10 23:10:14 +00004048 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004049 */
4050 clone_image=(*image);
4051 clone_info=(CacheInfo *) clone_image.cache;
4052 image->cache=ClonePixelCache(cache_info);
4053 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4054 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4055 cache_info->type=DiskCache;
4056 cache_info->offset=(*offset);
4057 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004058 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004059 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004060 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004061 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004062 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4063 return(status);
4064}
4065
4066/*
4067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4068% %
4069% %
4070% %
cristyc11dace2012-01-24 16:39:46 +00004071+ 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 +00004072% %
4073% %
4074% %
4075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4076%
cristyc11dace2012-01-24 16:39:46 +00004077% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4078% defined by the region rectangle and returns a pointer to the region. This
4079% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004080% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4081% pixels are transferred, otherwise a NULL is returned.
4082%
cristyc11dace2012-01-24 16:39:46 +00004083% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004084%
cristyc11dace2012-01-24 16:39:46 +00004085% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004086% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004087% const MagickBooleanType clone,NexusInfo *nexus_info,
4088% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004089%
4090% A description of each parameter follows:
4091%
4092% o image: the image.
4093%
4094% o x,y,columns,rows: These values define the perimeter of a region of
4095% pixels.
4096%
4097% o nexus_info: the cache nexus to set.
4098%
cristy65dbf172011-10-06 17:32:04 +00004099% o clone: clone the pixel cache.
4100%
cristy3ed852e2009-09-05 21:47:34 +00004101% o exception: return any errors or warnings in this structure.
4102%
4103*/
cristyc11dace2012-01-24 16:39:46 +00004104MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4105 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004106 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004107{
4108 CacheInfo
4109 *cache_info;
4110
4111 MagickOffsetType
4112 offset;
4113
4114 MagickSizeType
4115 number_pixels;
4116
4117 RectangleInfo
4118 region;
4119
4120 /*
4121 Validate pixel cache geometry.
4122 */
cristye7cc7cf2010-09-21 13:26:47 +00004123 assert(image != (const Image *) NULL);
4124 assert(image->signature == MagickSignature);
4125 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004126 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004127 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004128 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004129 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004130 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4131 {
4132 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004133 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004134 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004135 }
cristybb503372010-05-27 20:51:26 +00004136 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4137 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004138 {
4139 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004140 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004141 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004142 }
4143 offset=(MagickOffsetType) y*cache_info->columns+x;
4144 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004145 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004146 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4147 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4148 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004149 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004150 /*
4151 Return pixel cache.
4152 */
4153 region.x=x;
4154 region.y=y;
4155 region.width=columns;
4156 region.height=rows;
4157 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4158}
4159
4160/*
4161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4162% %
4163% %
4164% %
4165+ 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 %
4166% %
4167% %
4168% %
4169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4170%
4171% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4172% defined by the region rectangle and returns a pointer to the region. This
4173% region is subsequently transferred from the pixel cache with
4174% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4175% pixels are transferred, otherwise a NULL is returned.
4176%
4177% The format of the QueueAuthenticPixelsCache() method is:
4178%
cristy4c08aed2011-07-01 19:47:50 +00004179% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004180% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004181% ExceptionInfo *exception)
4182%
4183% A description of each parameter follows:
4184%
4185% o image: the image.
4186%
4187% o x,y,columns,rows: These values define the perimeter of a region of
4188% pixels.
4189%
4190% o exception: return any errors or warnings in this structure.
4191%
4192*/
cristy4c08aed2011-07-01 19:47:50 +00004193static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004194 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004195 ExceptionInfo *exception)
4196{
4197 CacheInfo
4198 *cache_info;
4199
cristy5c9e6f22010-09-17 17:31:01 +00004200 const int
4201 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004202
cristy4c08aed2011-07-01 19:47:50 +00004203 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004204 *q;
cristy4c08aed2011-07-01 19:47:50 +00004205
cristye7cc7cf2010-09-21 13:26:47 +00004206 assert(image != (const Image *) NULL);
4207 assert(image->signature == MagickSignature);
4208 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004209 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004210 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004211 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004212 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004213 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004214 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004215}
4216
4217/*
4218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4219% %
4220% %
4221% %
4222% Q u e u e A u t h e n t i c P i x e l s %
4223% %
4224% %
4225% %
4226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4227%
4228% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004229% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004230% region is returned, otherwise NULL is returned. The returned pointer may
4231% point to a temporary working buffer for the pixels or it may point to the
4232% final location of the pixels in memory.
4233%
4234% Write-only access means that any existing pixel values corresponding to
4235% the region are ignored. This is useful if the initial image is being
4236% created from scratch, or if the existing pixel values are to be
4237% completely replaced without need to refer to their pre-existing values.
4238% The application is free to read and write the pixel buffer returned by
4239% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4240% initialize the pixel array values. Initializing pixel array values is the
4241% application's responsibility.
4242%
4243% Performance is maximized if the selected region is part of one row, or
4244% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004245% pixels in-place (without a copy) if the image is in memory, or in a
4246% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004247% by the user.
4248%
4249% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004250% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4251% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4252% obtain the meta-content (of type void) corresponding to the region.
4253% Once the Quantum (and/or Quantum) array has been updated, the
4254% changes must be saved back to the underlying image using
4255% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004256%
4257% The format of the QueueAuthenticPixels() method is:
4258%
cristy4c08aed2011-07-01 19:47:50 +00004259% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004260% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004261% ExceptionInfo *exception)
4262%
4263% A description of each parameter follows:
4264%
4265% o image: the image.
4266%
4267% o x,y,columns,rows: These values define the perimeter of a region of
4268% pixels.
4269%
4270% o exception: return any errors or warnings in this structure.
4271%
4272*/
cristy4c08aed2011-07-01 19:47:50 +00004273MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004274 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004275 ExceptionInfo *exception)
4276{
4277 CacheInfo
4278 *cache_info;
4279
cristy2036f5c2010-09-19 21:18:17 +00004280 const int
4281 id = GetOpenMPThreadId();
4282
cristy4c08aed2011-07-01 19:47:50 +00004283 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004284 *q;
cristy4c08aed2011-07-01 19:47:50 +00004285
cristy3ed852e2009-09-05 21:47:34 +00004286 assert(image != (Image *) NULL);
4287 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004288 assert(image->cache != (Cache) NULL);
4289 cache_info=(CacheInfo *) image->cache;
4290 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004291 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004292 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004293 {
cristyc36c8822012-02-14 14:02:36 +00004294 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4295 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004296 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004297 }
cristy2036f5c2010-09-19 21:18:17 +00004298 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004299 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004300 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004301 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004302}
4303
4304/*
4305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4306% %
4307% %
4308% %
cristy4c08aed2011-07-01 19:47:50 +00004309+ 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 +00004310% %
4311% %
4312% %
4313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4314%
cristy4c08aed2011-07-01 19:47:50 +00004315% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004316% the pixel cache.
4317%
cristy4c08aed2011-07-01 19:47:50 +00004318% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004319%
cristy4c08aed2011-07-01 19:47:50 +00004320% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004321% NexusInfo *nexus_info,ExceptionInfo *exception)
4322%
4323% A description of each parameter follows:
4324%
4325% o cache_info: the pixel cache.
4326%
cristy4c08aed2011-07-01 19:47:50 +00004327% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004328%
4329% o exception: return any errors or warnings in this structure.
4330%
4331*/
cristy4c08aed2011-07-01 19:47:50 +00004332static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004333 NexusInfo *nexus_info,ExceptionInfo *exception)
4334{
4335 MagickOffsetType
4336 count,
4337 offset;
4338
4339 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004340 extent,
4341 length;
cristy3ed852e2009-09-05 21:47:34 +00004342
cristybb503372010-05-27 20:51:26 +00004343 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004344 y;
4345
cristy4c08aed2011-07-01 19:47:50 +00004346 register unsigned char
4347 *restrict q;
4348
cristybb503372010-05-27 20:51:26 +00004349 size_t
cristy3ed852e2009-09-05 21:47:34 +00004350 rows;
4351
cristy4c08aed2011-07-01 19:47:50 +00004352 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004353 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004354 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004355 return(MagickTrue);
4356 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4357 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004358 length=(MagickSizeType) nexus_info->region.width*
4359 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004360 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004361 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004362 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004363 switch (cache_info->type)
4364 {
4365 case MemoryCache:
4366 case MapCache:
4367 {
cristy4c08aed2011-07-01 19:47:50 +00004368 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004369 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004370
4371 /*
cristy4c08aed2011-07-01 19:47:50 +00004372 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004373 */
cristydd341db2010-03-04 19:06:38 +00004374 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004375 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004376 {
cristy48078b12010-09-23 17:11:01 +00004377 length=extent;
cristydd341db2010-03-04 19:06:38 +00004378 rows=1UL;
4379 }
cristy4c08aed2011-07-01 19:47:50 +00004380 p=(unsigned char *) cache_info->metacontent+offset*
4381 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004382 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004383 {
cristy8f036fe2010-09-18 02:02:00 +00004384 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004385 p+=cache_info->metacontent_extent*cache_info->columns;
4386 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004387 }
4388 break;
4389 }
4390 case DiskCache:
4391 {
4392 /*
cristy4c08aed2011-07-01 19:47:50 +00004393 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004394 */
4395 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4396 {
4397 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4398 cache_info->cache_filename);
4399 return(MagickFalse);
4400 }
cristydd341db2010-03-04 19:06:38 +00004401 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004402 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004403 {
cristy48078b12010-09-23 17:11:01 +00004404 length=extent;
cristydd341db2010-03-04 19:06:38 +00004405 rows=1UL;
4406 }
cristy48078b12010-09-23 17:11:01 +00004407 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004408 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004409 {
cristy48078b12010-09-23 17:11:01 +00004410 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004411 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004412 cache_info->metacontent_extent,length,(unsigned char *) q);
4413 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004414 break;
4415 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004416 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004417 }
cristyc11dace2012-01-24 16:39:46 +00004418 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4419 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004420 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004421 {
4422 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4423 cache_info->cache_filename);
4424 return(MagickFalse);
4425 }
4426 break;
4427 }
4428 default:
4429 break;
4430 }
4431 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004432 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004433 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004434 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004435 nexus_info->region.width,(double) nexus_info->region.height,(double)
4436 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004437 return(MagickTrue);
4438}
4439
4440/*
4441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4442% %
4443% %
4444% %
4445+ R e a d P i x e l C a c h e P i x e l s %
4446% %
4447% %
4448% %
4449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4450%
4451% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4452% cache.
4453%
4454% The format of the ReadPixelCachePixels() method is:
4455%
4456% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4457% NexusInfo *nexus_info,ExceptionInfo *exception)
4458%
4459% A description of each parameter follows:
4460%
4461% o cache_info: the pixel cache.
4462%
4463% o nexus_info: the cache nexus to read the pixels.
4464%
4465% o exception: return any errors or warnings in this structure.
4466%
4467*/
4468static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4469 NexusInfo *nexus_info,ExceptionInfo *exception)
4470{
4471 MagickOffsetType
4472 count,
4473 offset;
4474
4475 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004476 extent,
4477 length;
cristy3ed852e2009-09-05 21:47:34 +00004478
cristy4c08aed2011-07-01 19:47:50 +00004479 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004480 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004481
cristye076a6e2010-08-15 19:59:43 +00004482 register ssize_t
4483 y;
4484
cristybb503372010-05-27 20:51:26 +00004485 size_t
cristy3ed852e2009-09-05 21:47:34 +00004486 rows;
4487
cristy4c08aed2011-07-01 19:47:50 +00004488 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004489 return(MagickTrue);
4490 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4491 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004492 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004493 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004494 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004495 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004496 q=nexus_info->pixels;
4497 switch (cache_info->type)
4498 {
4499 case MemoryCache:
4500 case MapCache:
4501 {
cristy4c08aed2011-07-01 19:47:50 +00004502 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004503 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004504
4505 /*
4506 Read pixels from memory.
4507 */
cristydd341db2010-03-04 19:06:38 +00004508 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004509 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004510 {
cristy48078b12010-09-23 17:11:01 +00004511 length=extent;
cristydd341db2010-03-04 19:06:38 +00004512 rows=1UL;
4513 }
cristyed231572011-07-14 02:18:59 +00004514 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004515 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004516 {
cristy8f036fe2010-09-18 02:02:00 +00004517 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004518 p+=cache_info->number_channels*cache_info->columns;
4519 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004520 }
4521 break;
4522 }
4523 case DiskCache:
4524 {
4525 /*
4526 Read pixels from disk.
4527 */
4528 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4529 {
4530 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4531 cache_info->cache_filename);
4532 return(MagickFalse);
4533 }
cristydd341db2010-03-04 19:06:38 +00004534 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004535 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004536 {
cristy48078b12010-09-23 17:11:01 +00004537 length=extent;
cristydd341db2010-03-04 19:06:38 +00004538 rows=1UL;
4539 }
cristybb503372010-05-27 20:51:26 +00004540 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004541 {
4542 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004543 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004544 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004545 break;
4546 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004547 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004548 }
cristyc11dace2012-01-24 16:39:46 +00004549 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4550 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004551 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004552 {
4553 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4554 cache_info->cache_filename);
4555 return(MagickFalse);
4556 }
4557 break;
4558 }
4559 default:
4560 break;
4561 }
4562 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004563 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004564 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004565 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004566 nexus_info->region.width,(double) nexus_info->region.height,(double)
4567 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004568 return(MagickTrue);
4569}
4570
4571/*
4572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4573% %
4574% %
4575% %
4576+ R e f e r e n c e P i x e l C a c h e %
4577% %
4578% %
4579% %
4580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4581%
4582% ReferencePixelCache() increments the reference count associated with the
4583% pixel cache returning a pointer to the cache.
4584%
4585% The format of the ReferencePixelCache method is:
4586%
4587% Cache ReferencePixelCache(Cache cache_info)
4588%
4589% A description of each parameter follows:
4590%
4591% o cache_info: the pixel cache.
4592%
4593*/
cristya6577ff2011-09-02 19:54:26 +00004594MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004595{
4596 CacheInfo
4597 *cache_info;
4598
4599 assert(cache != (Cache *) NULL);
4600 cache_info=(CacheInfo *) cache;
4601 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004602 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004603 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004604 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004605 return(cache_info);
4606}
4607
4608/*
4609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4610% %
4611% %
4612% %
4613+ S e t P i x e l C a c h e M e t h o d s %
4614% %
4615% %
4616% %
4617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4618%
4619% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4620%
4621% The format of the SetPixelCacheMethods() method is:
4622%
4623% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4624%
4625% A description of each parameter follows:
4626%
4627% o cache: the pixel cache.
4628%
4629% o cache_methods: Specifies a pointer to a CacheMethods structure.
4630%
4631*/
cristya6577ff2011-09-02 19:54:26 +00004632MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004633{
4634 CacheInfo
4635 *cache_info;
4636
4637 GetOneAuthenticPixelFromHandler
4638 get_one_authentic_pixel_from_handler;
4639
4640 GetOneVirtualPixelFromHandler
4641 get_one_virtual_pixel_from_handler;
4642
4643 /*
4644 Set cache pixel methods.
4645 */
4646 assert(cache != (Cache) NULL);
4647 assert(cache_methods != (CacheMethods *) NULL);
4648 cache_info=(CacheInfo *) cache;
4649 assert(cache_info->signature == MagickSignature);
4650 if (cache_info->debug != MagickFalse)
4651 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4652 cache_info->filename);
4653 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4654 cache_info->methods.get_virtual_pixel_handler=
4655 cache_methods->get_virtual_pixel_handler;
4656 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4657 cache_info->methods.destroy_pixel_handler=
4658 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004659 if (cache_methods->get_virtual_metacontent_from_handler !=
4660 (GetVirtualMetacontentFromHandler) NULL)
4661 cache_info->methods.get_virtual_metacontent_from_handler=
4662 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004663 if (cache_methods->get_authentic_pixels_handler !=
4664 (GetAuthenticPixelsHandler) NULL)
4665 cache_info->methods.get_authentic_pixels_handler=
4666 cache_methods->get_authentic_pixels_handler;
4667 if (cache_methods->queue_authentic_pixels_handler !=
4668 (QueueAuthenticPixelsHandler) NULL)
4669 cache_info->methods.queue_authentic_pixels_handler=
4670 cache_methods->queue_authentic_pixels_handler;
4671 if (cache_methods->sync_authentic_pixels_handler !=
4672 (SyncAuthenticPixelsHandler) NULL)
4673 cache_info->methods.sync_authentic_pixels_handler=
4674 cache_methods->sync_authentic_pixels_handler;
4675 if (cache_methods->get_authentic_pixels_from_handler !=
4676 (GetAuthenticPixelsFromHandler) NULL)
4677 cache_info->methods.get_authentic_pixels_from_handler=
4678 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004679 if (cache_methods->get_authentic_metacontent_from_handler !=
4680 (GetAuthenticMetacontentFromHandler) NULL)
4681 cache_info->methods.get_authentic_metacontent_from_handler=
4682 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004683 get_one_virtual_pixel_from_handler=
4684 cache_info->methods.get_one_virtual_pixel_from_handler;
4685 if (get_one_virtual_pixel_from_handler !=
4686 (GetOneVirtualPixelFromHandler) NULL)
4687 cache_info->methods.get_one_virtual_pixel_from_handler=
4688 cache_methods->get_one_virtual_pixel_from_handler;
4689 get_one_authentic_pixel_from_handler=
4690 cache_methods->get_one_authentic_pixel_from_handler;
4691 if (get_one_authentic_pixel_from_handler !=
4692 (GetOneAuthenticPixelFromHandler) NULL)
4693 cache_info->methods.get_one_authentic_pixel_from_handler=
4694 cache_methods->get_one_authentic_pixel_from_handler;
4695}
4696
4697/*
4698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4699% %
4700% %
4701% %
4702+ S e t P i x e l C a c h e N e x u s P i x e l s %
4703% %
4704% %
4705% %
4706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4707%
4708% SetPixelCacheNexusPixels() defines the region of the cache for the
4709% specified cache nexus.
4710%
4711% The format of the SetPixelCacheNexusPixels() method is:
4712%
cristy4c08aed2011-07-01 19:47:50 +00004713% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004714% const RectangleInfo *region,NexusInfo *nexus_info,
4715% ExceptionInfo *exception)
4716%
4717% A description of each parameter follows:
4718%
4719% o image: the image.
4720%
4721% o region: A pointer to the RectangleInfo structure that defines the
4722% region of this particular cache nexus.
4723%
4724% o nexus_info: the cache nexus to set.
4725%
4726% o exception: return any errors or warnings in this structure.
4727%
4728*/
cristyabd6e372010-09-15 19:11:26 +00004729
4730static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4731 NexusInfo *nexus_info,ExceptionInfo *exception)
4732{
4733 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4734 return(MagickFalse);
4735 nexus_info->mapped=MagickFalse;
cristy64c3edf2012-04-13 18:50:13 +00004736 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00004737 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004738 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004739 {
4740 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004741 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004742 nexus_info->length);
4743 }
cristy4c08aed2011-07-01 19:47:50 +00004744 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004745 {
4746 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004747 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004748 cache_info->filename);
4749 return(MagickFalse);
4750 }
4751 return(MagickTrue);
4752}
4753
cristy4c08aed2011-07-01 19:47:50 +00004754static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004755 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4756{
4757 CacheInfo
4758 *cache_info;
4759
4760 MagickBooleanType
4761 status;
4762
cristy3ed852e2009-09-05 21:47:34 +00004763 MagickSizeType
4764 length,
4765 number_pixels;
4766
cristy3ed852e2009-09-05 21:47:34 +00004767 cache_info=(CacheInfo *) image->cache;
4768 assert(cache_info->signature == MagickSignature);
4769 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004770 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004771 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004772 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004773 {
cristybb503372010-05-27 20:51:26 +00004774 ssize_t
cristybad067a2010-02-15 17:20:55 +00004775 x,
4776 y;
cristy3ed852e2009-09-05 21:47:34 +00004777
cristyeaedf062010-05-29 22:36:02 +00004778 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4779 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004780 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4781 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004782 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004783 ((nexus_info->region.width == cache_info->columns) ||
4784 ((nexus_info->region.width % cache_info->columns) == 0)))))
4785 {
4786 MagickOffsetType
4787 offset;
4788
4789 /*
4790 Pixels are accessed directly from memory.
4791 */
4792 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4793 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004794 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004795 offset;
4796 nexus_info->metacontent=(void *) NULL;
4797 if (cache_info->metacontent_extent != 0)
4798 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4799 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00004800 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004801 }
4802 }
4803 /*
4804 Pixels are stored in a cache region until they are synced to the cache.
4805 */
4806 number_pixels=(MagickSizeType) nexus_info->region.width*
4807 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004808 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004809 if (cache_info->metacontent_extent != 0)
4810 length+=number_pixels*cache_info->metacontent_extent;
4811 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004812 {
4813 nexus_info->length=length;
4814 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4815 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004816 {
4817 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004818 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004819 }
cristy3ed852e2009-09-05 21:47:34 +00004820 }
4821 else
4822 if (nexus_info->length != length)
4823 {
4824 RelinquishCacheNexusPixels(nexus_info);
4825 nexus_info->length=length;
4826 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4827 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004828 {
4829 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004830 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004831 }
cristy3ed852e2009-09-05 21:47:34 +00004832 }
4833 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004834 nexus_info->metacontent=(void *) NULL;
4835 if (cache_info->metacontent_extent != 0)
4836 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004837 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004838 return(nexus_info->pixels);
4839}
4840
4841/*
4842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4843% %
4844% %
4845% %
4846% 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 %
4847% %
4848% %
4849% %
4850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4851%
4852% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4853% pixel cache and returns the previous setting. A virtual pixel is any pixel
4854% access that is outside the boundaries of the image cache.
4855%
4856% The format of the SetPixelCacheVirtualMethod() method is:
4857%
cristy387430f2012-02-07 13:09:46 +00004858% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4859% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004860%
4861% A description of each parameter follows:
4862%
4863% o image: the image.
4864%
4865% o virtual_pixel_method: choose the type of virtual pixel.
4866%
cristy387430f2012-02-07 13:09:46 +00004867% o exception: return any errors or warnings in this structure.
4868%
cristy3ed852e2009-09-05 21:47:34 +00004869*/
cristy3d4cb882012-02-07 19:11:26 +00004870
4871static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4872 ExceptionInfo *exception)
4873{
cristy23d198a2012-03-13 13:48:08 +00004874 CacheView
4875 *image_view;
4876
cristy3d4cb882012-02-07 19:11:26 +00004877 CacheInfo
4878 *cache_info;
4879
4880 MagickBooleanType
4881 status;
4882
4883 ssize_t
4884 y;
4885
4886 assert(image != (Image *) NULL);
4887 assert(image->signature == MagickSignature);
4888 if (image->debug != MagickFalse)
4889 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4890 assert(image->cache != (Cache) NULL);
4891 cache_info=(CacheInfo *) image->cache;
4892 assert(cache_info->signature == MagickSignature);
4893 image->matte=MagickTrue;
4894 status=MagickTrue;
cristydb070952012-04-20 14:33:00 +00004895 image_view=AcquireAuthenticCacheView(image,exception);
cristy3d4cb882012-02-07 19:11:26 +00004896#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristydb070952012-04-20 14:33:00 +00004897 #pragma omp parallel for schedule(static) shared(status)
cristy3d4cb882012-02-07 19:11:26 +00004898#endif
4899 for (y=0; y < (ssize_t) image->rows; y++)
4900 {
cristy3d4cb882012-02-07 19:11:26 +00004901 register Quantum
4902 *restrict q;
4903
4904 register ssize_t
4905 x;
4906
4907 if (status == MagickFalse)
4908 continue;
cristy23d198a2012-03-13 13:48:08 +00004909 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004910 if (q == (Quantum *) NULL)
4911 {
4912 status=MagickFalse;
4913 continue;
4914 }
4915 for (x=0; x < (ssize_t) image->columns; x++)
4916 {
4917 SetPixelAlpha(image,alpha,q);
4918 q+=GetPixelChannels(image);
4919 }
cristy23d198a2012-03-13 13:48:08 +00004920 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004921 }
cristy23d198a2012-03-13 13:48:08 +00004922 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004923 return(status);
4924}
4925
cristy387430f2012-02-07 13:09:46 +00004926MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4927 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004928{
4929 CacheInfo
4930 *cache_info;
4931
4932 VirtualPixelMethod
4933 method;
4934
4935 assert(image != (Image *) NULL);
4936 assert(image->signature == MagickSignature);
4937 if (image->debug != MagickFalse)
4938 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4939 assert(image->cache != (Cache) NULL);
4940 cache_info=(CacheInfo *) image->cache;
4941 assert(cache_info->signature == MagickSignature);
4942 method=cache_info->virtual_pixel_method;
4943 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004944 switch (virtual_pixel_method)
4945 {
4946 case BackgroundVirtualPixelMethod:
4947 {
4948 if ((image->background_color.matte != MagickFalse) &&
4949 (image->matte == MagickFalse))
cristy3d4cb882012-02-07 19:11:26 +00004950 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004951 break;
4952 }
4953 case TransparentVirtualPixelMethod:
4954 {
4955 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00004956 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004957 break;
4958 }
4959 default:
4960 break;
4961 }
cristy3ed852e2009-09-05 21:47:34 +00004962 return(method);
4963}
4964
4965/*
4966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4967% %
4968% %
4969% %
4970+ 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 %
4971% %
4972% %
4973% %
4974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4975%
4976% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4977% in-memory or disk cache. The method returns MagickTrue if the pixel region
4978% is synced, otherwise MagickFalse.
4979%
4980% The format of the SyncAuthenticPixelCacheNexus() method is:
4981%
4982% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4983% NexusInfo *nexus_info,ExceptionInfo *exception)
4984%
4985% A description of each parameter follows:
4986%
4987% o image: the image.
4988%
4989% o nexus_info: the cache nexus to sync.
4990%
4991% o exception: return any errors or warnings in this structure.
4992%
4993*/
cristya6577ff2011-09-02 19:54:26 +00004994MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004995 NexusInfo *nexus_info,ExceptionInfo *exception)
4996{
4997 CacheInfo
4998 *cache_info;
4999
5000 MagickBooleanType
5001 status;
5002
5003 /*
5004 Transfer pixels to the cache.
5005 */
5006 assert(image != (Image *) NULL);
5007 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005008 if (image->cache == (Cache) NULL)
5009 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5010 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005011 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005012 if (cache_info->type == UndefinedCache)
5013 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005014 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005015 return(MagickTrue);
5016 assert(cache_info->signature == MagickSignature);
5017 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005018 if ((cache_info->metacontent_extent != 0) &&
5019 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005020 return(MagickFalse);
5021 return(status);
5022}
5023
5024/*
5025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5026% %
5027% %
5028% %
5029+ S y n c A u t h e n t i c P i x e l C a c h e %
5030% %
5031% %
5032% %
5033%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5034%
5035% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5036% or disk cache. The method returns MagickTrue if the pixel region is synced,
5037% otherwise MagickFalse.
5038%
5039% The format of the SyncAuthenticPixelsCache() method is:
5040%
5041% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5042% ExceptionInfo *exception)
5043%
5044% A description of each parameter follows:
5045%
5046% o image: the image.
5047%
5048% o exception: return any errors or warnings in this structure.
5049%
5050*/
5051static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5052 ExceptionInfo *exception)
5053{
5054 CacheInfo
5055 *cache_info;
5056
cristy5c9e6f22010-09-17 17:31:01 +00005057 const int
5058 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005059
cristy4c08aed2011-07-01 19:47:50 +00005060 MagickBooleanType
5061 status;
5062
cristye7cc7cf2010-09-21 13:26:47 +00005063 assert(image != (Image *) NULL);
5064 assert(image->signature == MagickSignature);
5065 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005066 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005067 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005068 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005069 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5070 exception);
5071 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005072}
5073
5074/*
5075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5076% %
5077% %
5078% %
5079% S y n c A u t h e n t i c P i x e l s %
5080% %
5081% %
5082% %
5083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5084%
5085% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5086% The method returns MagickTrue if the pixel region is flushed, otherwise
5087% MagickFalse.
5088%
5089% The format of the SyncAuthenticPixels() method is:
5090%
5091% MagickBooleanType SyncAuthenticPixels(Image *image,
5092% ExceptionInfo *exception)
5093%
5094% A description of each parameter follows:
5095%
5096% o image: the image.
5097%
5098% o exception: return any errors or warnings in this structure.
5099%
5100*/
5101MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5102 ExceptionInfo *exception)
5103{
5104 CacheInfo
5105 *cache_info;
5106
cristy2036f5c2010-09-19 21:18:17 +00005107 const int
5108 id = GetOpenMPThreadId();
5109
cristy4c08aed2011-07-01 19:47:50 +00005110 MagickBooleanType
5111 status;
5112
cristy3ed852e2009-09-05 21:47:34 +00005113 assert(image != (Image *) NULL);
5114 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005115 assert(image->cache != (Cache) NULL);
5116 cache_info=(CacheInfo *) image->cache;
5117 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005118 if (cache_info->methods.sync_authentic_pixels_handler !=
5119 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005120 {
5121 status=cache_info->methods.sync_authentic_pixels_handler(image,
5122 exception);
5123 return(status);
5124 }
cristy2036f5c2010-09-19 21:18:17 +00005125 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005126 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5127 exception);
5128 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005129}
5130
5131/*
5132%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5133% %
5134% %
5135% %
cristyd1dd6e42011-09-04 01:46:08 +00005136+ 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 +00005137% %
5138% %
5139% %
5140%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5141%
5142% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5143% The method returns MagickTrue if the pixel region is flushed, otherwise
5144% MagickFalse.
5145%
5146% The format of the SyncImagePixelCache() method is:
5147%
5148% MagickBooleanType SyncImagePixelCache(Image *image,
5149% ExceptionInfo *exception)
5150%
5151% A description of each parameter follows:
5152%
5153% o image: the image.
5154%
5155% o exception: return any errors or warnings in this structure.
5156%
5157*/
cristyd1dd6e42011-09-04 01:46:08 +00005158MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005159 ExceptionInfo *exception)
5160{
5161 CacheInfo
5162 *cache_info;
5163
5164 assert(image != (Image *) NULL);
5165 assert(exception != (ExceptionInfo *) NULL);
5166 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5167 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5168}
5169
5170/*
5171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5172% %
5173% %
5174% %
cristy4c08aed2011-07-01 19:47:50 +00005175+ 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 +00005176% %
5177% %
5178% %
5179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5180%
cristy4c08aed2011-07-01 19:47:50 +00005181% WritePixelCacheMetacontent() writes the meta-content to the specified region
5182% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005183%
cristy4c08aed2011-07-01 19:47:50 +00005184% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005185%
cristy4c08aed2011-07-01 19:47:50 +00005186% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005187% NexusInfo *nexus_info,ExceptionInfo *exception)
5188%
5189% A description of each parameter follows:
5190%
5191% o cache_info: the pixel cache.
5192%
cristy4c08aed2011-07-01 19:47:50 +00005193% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005194%
5195% o exception: return any errors or warnings in this structure.
5196%
5197*/
cristy4c08aed2011-07-01 19:47:50 +00005198static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005199 NexusInfo *nexus_info,ExceptionInfo *exception)
5200{
5201 MagickOffsetType
5202 count,
5203 offset;
5204
5205 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005206 extent,
5207 length;
cristy3ed852e2009-09-05 21:47:34 +00005208
cristy4c08aed2011-07-01 19:47:50 +00005209 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005210 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005211
cristybb503372010-05-27 20:51:26 +00005212 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005213 y;
5214
cristybb503372010-05-27 20:51:26 +00005215 size_t
cristy3ed852e2009-09-05 21:47:34 +00005216 rows;
5217
cristy4c08aed2011-07-01 19:47:50 +00005218 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005219 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005220 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005221 return(MagickTrue);
5222 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5223 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005224 length=(MagickSizeType) nexus_info->region.width*
5225 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005226 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005227 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005228 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005229 switch (cache_info->type)
5230 {
5231 case MemoryCache:
5232 case MapCache:
5233 {
cristy4c08aed2011-07-01 19:47:50 +00005234 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005235 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005236
5237 /*
cristy4c08aed2011-07-01 19:47:50 +00005238 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005239 */
cristydd341db2010-03-04 19:06:38 +00005240 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005241 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005242 {
cristy48078b12010-09-23 17:11:01 +00005243 length=extent;
cristydd341db2010-03-04 19:06:38 +00005244 rows=1UL;
5245 }
cristy4c08aed2011-07-01 19:47:50 +00005246 q=(unsigned char *) cache_info->metacontent+offset*
5247 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005248 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005249 {
cristy8f036fe2010-09-18 02:02:00 +00005250 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005251 p+=nexus_info->region.width*cache_info->metacontent_extent;
5252 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005253 }
5254 break;
5255 }
5256 case DiskCache:
5257 {
5258 /*
cristy4c08aed2011-07-01 19:47:50 +00005259 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005260 */
5261 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5262 {
5263 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5264 cache_info->cache_filename);
5265 return(MagickFalse);
5266 }
cristydd341db2010-03-04 19:06:38 +00005267 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005268 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005269 {
cristy48078b12010-09-23 17:11:01 +00005270 length=extent;
cristydd341db2010-03-04 19:06:38 +00005271 rows=1UL;
5272 }
cristy48078b12010-09-23 17:11:01 +00005273 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005274 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005275 {
cristy48078b12010-09-23 17:11:01 +00005276 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005277 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005278 cache_info->metacontent_extent,length,(const unsigned char *) p);
5279 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005280 break;
cristy4c08aed2011-07-01 19:47:50 +00005281 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005282 offset+=cache_info->columns;
5283 }
cristyc11dace2012-01-24 16:39:46 +00005284 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5285 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005286 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005287 {
5288 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5289 cache_info->cache_filename);
5290 return(MagickFalse);
5291 }
5292 break;
5293 }
5294 default:
5295 break;
5296 }
5297 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005298 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005299 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005300 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005301 nexus_info->region.width,(double) nexus_info->region.height,(double)
5302 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005303 return(MagickTrue);
5304}
5305
5306/*
5307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5308% %
5309% %
5310% %
5311+ W r i t e C a c h e P i x e l s %
5312% %
5313% %
5314% %
5315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5316%
5317% WritePixelCachePixels() writes image pixels to the specified region of the
5318% pixel cache.
5319%
5320% The format of the WritePixelCachePixels() method is:
5321%
5322% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5323% NexusInfo *nexus_info,ExceptionInfo *exception)
5324%
5325% A description of each parameter follows:
5326%
5327% o cache_info: the pixel cache.
5328%
5329% o nexus_info: the cache nexus to write the pixels.
5330%
5331% o exception: return any errors or warnings in this structure.
5332%
5333*/
5334static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5335 NexusInfo *nexus_info,ExceptionInfo *exception)
5336{
5337 MagickOffsetType
5338 count,
5339 offset;
5340
5341 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005342 extent,
5343 length;
cristy3ed852e2009-09-05 21:47:34 +00005344
cristy4c08aed2011-07-01 19:47:50 +00005345 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005346 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005347
cristybb503372010-05-27 20:51:26 +00005348 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005349 y;
5350
cristybb503372010-05-27 20:51:26 +00005351 size_t
cristy3ed852e2009-09-05 21:47:34 +00005352 rows;
5353
cristy4c08aed2011-07-01 19:47:50 +00005354 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005355 return(MagickTrue);
5356 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5357 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005358 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005359 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005360 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005361 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005362 p=nexus_info->pixels;
5363 switch (cache_info->type)
5364 {
5365 case MemoryCache:
5366 case MapCache:
5367 {
cristy4c08aed2011-07-01 19:47:50 +00005368 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005369 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005370
5371 /*
5372 Write pixels to memory.
5373 */
cristydd341db2010-03-04 19:06:38 +00005374 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005375 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005376 {
cristy48078b12010-09-23 17:11:01 +00005377 length=extent;
cristydd341db2010-03-04 19:06:38 +00005378 rows=1UL;
5379 }
cristyed231572011-07-14 02:18:59 +00005380 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005381 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005382 {
cristy8f036fe2010-09-18 02:02:00 +00005383 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005384 p+=nexus_info->region.width*cache_info->number_channels;
5385 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005386 }
5387 break;
5388 }
5389 case DiskCache:
5390 {
5391 /*
5392 Write pixels to disk.
5393 */
5394 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5395 {
5396 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5397 cache_info->cache_filename);
5398 return(MagickFalse);
5399 }
cristydd341db2010-03-04 19:06:38 +00005400 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005401 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005402 {
cristy48078b12010-09-23 17:11:01 +00005403 length=extent;
cristydd341db2010-03-04 19:06:38 +00005404 rows=1UL;
5405 }
cristybb503372010-05-27 20:51:26 +00005406 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005407 {
5408 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005409 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005410 p);
5411 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005412 break;
cristyed231572011-07-14 02:18:59 +00005413 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005414 offset+=cache_info->columns;
5415 }
cristyc11dace2012-01-24 16:39:46 +00005416 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5417 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005418 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005419 {
5420 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5421 cache_info->cache_filename);
5422 return(MagickFalse);
5423 }
5424 break;
5425 }
5426 default:
5427 break;
5428 }
5429 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005430 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005431 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005432 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005433 nexus_info->region.width,(double) nexus_info->region.height,(double)
5434 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005435 return(MagickTrue);
5436}