blob: 249db2d0a1c33b0dfb48f5bc38a383774b7f47da [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)
cristyac245f82012-05-05 17:13:57 +0000204 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
cristy3ed852e2009-09-05 21:47:34 +0000205 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
206 if (cache_info->nexus_info == (NexusInfo **) NULL)
207 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000208 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000209 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000210 cache_info->disk_semaphore=AllocateSemaphoreInfo();
211 cache_info->debug=IsEventLogging();
212 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000213 return((Cache ) cache_info);
214}
215
216/*
217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218% %
219% %
220% %
221% A c q u i r e P i x e l C a c h e N e x u s %
222% %
223% %
224% %
225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226%
227% AcquirePixelCacheNexus() allocates the NexusInfo structure.
228%
229% The format of the AcquirePixelCacheNexus method is:
230%
cristybb503372010-05-27 20:51:26 +0000231% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000232%
233% A description of each parameter follows:
234%
235% o number_threads: the number of nexus threads.
236%
237*/
cristya6577ff2011-09-02 19:54:26 +0000238MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000239{
cristy3ed852e2009-09-05 21:47:34 +0000240 NexusInfo
241 **nexus_info;
242
cristye076a6e2010-08-15 19:59:43 +0000243 register ssize_t
244 i;
245
cristy64c3edf2012-04-13 18:50:13 +0000246 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000247 sizeof(*nexus_info));
248 if (nexus_info == (NexusInfo **) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000250 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
251 sizeof(**nexus_info));
252 if (nexus_info[0] == (NexusInfo *) NULL)
253 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
254 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000255 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000256 {
cristye5f87c82012-02-14 12:44:17 +0000257 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000258 nexus_info[i]->signature=MagickSignature;
259 }
260 return(nexus_info);
261}
262
263/*
264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265% %
266% %
267% %
cristyd43a46b2010-01-21 02:13:41 +0000268+ A c q u i r e P i x e l C a c h e P i x e l s %
269% %
270% %
271% %
272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273%
274% AcquirePixelCachePixels() returns the pixels associated with the specified
275% image.
276%
277% The format of the AcquirePixelCachePixels() method is:
278%
279% const void *AcquirePixelCachePixels(const Image *image,
280% MagickSizeType *length,ExceptionInfo *exception)
281%
282% A description of each parameter follows:
283%
284% o image: the image.
285%
286% o length: the pixel cache length.
287%
288% o exception: return any errors or warnings in this structure.
289%
290*/
cristyd1dd6e42011-09-04 01:46:08 +0000291MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000292 MagickSizeType *length,ExceptionInfo *exception)
293{
294 CacheInfo
295 *cache_info;
296
297 assert(image != (const Image *) NULL);
298 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000299 assert(exception != (ExceptionInfo *) NULL);
300 assert(exception->signature == MagickSignature);
301 assert(image->cache != (Cache) NULL);
302 cache_info=(CacheInfo *) image->cache;
303 assert(cache_info->signature == MagickSignature);
304 *length=0;
305 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
306 return((const void *) NULL);
307 *length=cache_info->length;
308 return((const void *) cache_info->pixels);
309}
310
311/*
312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313% %
314% %
315% %
cristyf34a1452009-10-24 22:29:27 +0000316+ C a c h e C o m p o n e n t G e n e s i s %
317% %
318% %
319% %
320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321%
322% CacheComponentGenesis() instantiates the cache component.
323%
324% The format of the CacheComponentGenesis method is:
325%
326% MagickBooleanType CacheComponentGenesis(void)
327%
328*/
cristy5ff4eaf2011-09-03 01:38:02 +0000329MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000330{
cristy165b6092009-10-26 13:52:10 +0000331 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000332 return(MagickTrue);
333}
334
335/*
336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337% %
338% %
339% %
340+ C a c h e C o m p o n e n t T e r m i n u s %
341% %
342% %
343% %
344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345%
346% CacheComponentTerminus() destroys the cache component.
347%
348% The format of the CacheComponentTerminus() method is:
349%
350% CacheComponentTerminus(void)
351%
352*/
cristy5ff4eaf2011-09-03 01:38:02 +0000353MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000354{
cristy18b17442009-10-25 18:36:48 +0000355 if (cache_semaphore == (SemaphoreInfo *) NULL)
356 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000357 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000358 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000359 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000360 DestroySemaphoreInfo(&cache_semaphore);
361}
362
363/*
364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365% %
366% %
367% %
cristy3ed852e2009-09-05 21:47:34 +0000368+ C l o n e P i x e l C a c h e %
369% %
370% %
371% %
372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373%
374% ClonePixelCache() clones a pixel cache.
375%
376% The format of the ClonePixelCache() method is:
377%
378% Cache ClonePixelCache(const Cache cache)
379%
380% A description of each parameter follows:
381%
382% o cache: the pixel cache.
383%
384*/
cristya6577ff2011-09-02 19:54:26 +0000385MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000386{
387 CacheInfo
388 *clone_info;
389
390 const CacheInfo
391 *cache_info;
392
cristy9f027d12011-09-21 01:17:17 +0000393 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000394 cache_info=(const CacheInfo *) cache;
395 assert(cache_info->signature == MagickSignature);
396 if (cache_info->debug != MagickFalse)
397 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
398 cache_info->filename);
399 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
400 if (clone_info == (Cache) NULL)
401 return((Cache) NULL);
402 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
403 return((Cache ) clone_info);
404}
405
406/*
407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408% %
409% %
410% %
cristy60c44a82009-10-07 00:58:49 +0000411+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000412% %
413% %
414% %
415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
416% ClonePixelCachePixels() clones the source pixel cache to the destination
417% cache.
418%
419% The format of the ClonePixelCachePixels() method is:
420%
421% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
422% CacheInfo *source_info,ExceptionInfo *exception)
423%
424% A description of each parameter follows:
425%
426% o cache_info: the pixel cache.
427%
428% o source_info: the source pixel cache.
429%
430% o exception: return any errors or warnings in this structure.
431%
432*/
433
434static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
435{
436 int
437 status;
438
cristy5ee247a2010-02-12 15:42:34 +0000439 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000440 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000441 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000442 {
443 status=close(cache_info->file);
444 cache_info->file=(-1);
445 RelinquishMagickResource(FileResource,1);
446 }
cristyf84a1932010-01-03 18:00:18 +0000447 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000448 return(status == -1 ? MagickFalse : MagickTrue);
449}
450
cristy3ed852e2009-09-05 21:47:34 +0000451static inline MagickSizeType MagickMax(const MagickSizeType x,
452 const MagickSizeType y)
453{
454 if (x > y)
455 return(x);
456 return(y);
457}
458
459static inline MagickSizeType MagickMin(const MagickSizeType x,
460 const MagickSizeType y)
461{
462 if (x < y)
463 return(x);
464 return(y);
465}
466
467static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
468 const MapMode mode)
469{
470 int
471 file;
472
473 /*
474 Open pixel cache on disk.
475 */
cristyf84a1932010-01-03 18:00:18 +0000476 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000477 if (cache_info->file != -1)
478 {
cristyf84a1932010-01-03 18:00:18 +0000479 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000480 return(MagickTrue); /* cache already open */
481 }
cristy3ed852e2009-09-05 21:47:34 +0000482 if (*cache_info->cache_filename == '\0')
483 file=AcquireUniqueFileResource(cache_info->cache_filename);
484 else
485 switch (mode)
486 {
487 case ReadMode:
488 {
cristy18c6c272011-09-23 14:40:37 +0000489 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000490 break;
491 }
492 case WriteMode:
493 {
cristy18c6c272011-09-23 14:40:37 +0000494 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
495 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000496 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000497 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000498 break;
499 }
500 case IOMode:
501 default:
502 {
cristy18c6c272011-09-23 14:40:37 +0000503 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000504 O_EXCL,S_MODE);
505 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000506 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000507 break;
508 }
509 }
510 if (file == -1)
511 {
cristyf84a1932010-01-03 18:00:18 +0000512 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000513 return(MagickFalse);
514 }
515 (void) AcquireMagickResource(FileResource,1);
516 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000517 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000518 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000519 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000520 return(MagickTrue);
521}
522
523static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
524 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000525 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000526{
527 register MagickOffsetType
528 i;
529
530 ssize_t
531 count;
532
cristy08a88202010-03-04 19:18:05 +0000533 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000534#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000535 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000536 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000537 {
cristyf84a1932010-01-03 18:00:18 +0000538 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000539 return((MagickOffsetType) -1);
540 }
541#endif
542 count=0;
543 for (i=0; i < (MagickOffsetType) length; i+=count)
544 {
545#if !defined(MAGICKCORE_HAVE_PREAD)
546 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
547 (MagickSizeType) SSIZE_MAX));
548#else
549 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000550 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000551#endif
552 if (count > 0)
553 continue;
554 count=0;
555 if (errno != EINTR)
556 {
557 i=(-1);
558 break;
559 }
560 }
561#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563#endif
564 return(i);
565}
566
567static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
568 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000569 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000570{
571 register MagickOffsetType
572 i;
573
574 ssize_t
575 count;
576
cristy08a88202010-03-04 19:18:05 +0000577 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000578#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000579 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000580 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000581 {
cristyf84a1932010-01-03 18:00:18 +0000582 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000583 return((MagickOffsetType) -1);
584 }
585#endif
586 count=0;
587 for (i=0; i < (MagickOffsetType) length; i+=count)
588 {
589#if !defined(MAGICKCORE_HAVE_PWRITE)
590 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
591 (MagickSizeType) SSIZE_MAX));
592#else
593 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000594 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000595#endif
596 if (count > 0)
597 continue;
598 count=0;
599 if (errno != EINTR)
600 {
601 i=(-1);
602 break;
603 }
604 }
605#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607#endif
608 return(i);
609}
610
cristy4c08aed2011-07-01 19:47:50 +0000611static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000612 CacheInfo *cache_info,ExceptionInfo *exception)
613{
614 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000615 count;
cristy3ed852e2009-09-05 21:47:34 +0000616
cristy4c08aed2011-07-01 19:47:50 +0000617 register MagickOffsetType
618 i;
cristye076a6e2010-08-15 19:59:43 +0000619
cristybb503372010-05-27 20:51:26 +0000620 size_t
cristy4c08aed2011-07-01 19:47:50 +0000621 length;
cristy3ed852e2009-09-05 21:47:34 +0000622
cristy4c08aed2011-07-01 19:47:50 +0000623 unsigned char
624 *blob;
625
626 /*
627 Clone pixel cache (both caches on disk).
628 */
cristy3ed852e2009-09-05 21:47:34 +0000629 if (cache_info->debug != MagickFalse)
630 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000631 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000632 sizeof(*blob));
633 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000634 {
cristy4c08aed2011-07-01 19:47:50 +0000635 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000636 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000637 cache_info->filename);
638 return(MagickFalse);
639 }
cristy3dedf062011-07-02 14:07:40 +0000640 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000641 {
642 blob=(unsigned char *) RelinquishMagickMemory(blob);
643 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
644 cache_info->cache_filename);
645 return(MagickFalse);
646 }
cristy3dedf062011-07-02 14:07:40 +0000647 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000648 {
649 (void) ClosePixelCacheOnDisk(cache_info);
650 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000651 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
652 clone_info->cache_filename);
653 return(MagickFalse);
654 }
cristy4c08aed2011-07-01 19:47:50 +0000655 count=0;
656 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000657 {
cristy4c08aed2011-07-01 19:47:50 +0000658 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
659 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
660 blob);
661 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000662 {
cristy4c08aed2011-07-01 19:47:50 +0000663 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
664 cache_info->cache_filename);
665 break;
cristy3ed852e2009-09-05 21:47:34 +0000666 }
cristy4c08aed2011-07-01 19:47:50 +0000667 length=(size_t) count;
668 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
669 if ((MagickSizeType) count != length)
670 {
671 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
672 clone_info->cache_filename);
673 break;
674 }
675 }
676 (void) ClosePixelCacheOnDisk(clone_info);
677 (void) ClosePixelCacheOnDisk(cache_info);
678 blob=(unsigned char *) RelinquishMagickMemory(blob);
679 if (i < (MagickOffsetType) cache_info->length)
680 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000681 return(MagickTrue);
682}
683
cristyfd24a062012-01-02 14:46:34 +0000684static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000685 CacheInfo *cache_info,ExceptionInfo *exception)
686{
687 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000688 count;
cristy3ed852e2009-09-05 21:47:34 +0000689
cristy4c08aed2011-07-01 19:47:50 +0000690 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000691 {
cristy3ed852e2009-09-05 21:47:34 +0000692 /*
cristy4c08aed2011-07-01 19:47:50 +0000693 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000694 */
cristy4c08aed2011-07-01 19:47:50 +0000695 if (cache_info->debug != MagickFalse)
696 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
697 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
698 cache_info->length);
699 return(MagickTrue);
700 }
701 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
702 {
703 /*
704 Clone pixel cache (one cache on disk, one in memory).
705 */
706 if (cache_info->debug != MagickFalse)
707 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
708 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000709 {
cristy4c08aed2011-07-01 19:47:50 +0000710 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000711 cache_info->cache_filename);
712 return(MagickFalse);
713 }
cristy4c08aed2011-07-01 19:47:50 +0000714 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
715 cache_info->length,(unsigned char *) clone_info->pixels);
716 (void) ClosePixelCacheOnDisk(cache_info);
717 if ((MagickSizeType) count != cache_info->length)
718 {
719 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
720 cache_info->cache_filename);
721 return(MagickFalse);
722 }
723 return(MagickTrue);
724 }
725 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
726 {
727 /*
728 Clone pixel cache (one cache on disk, one in memory).
729 */
730 if (clone_info->debug != MagickFalse)
731 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
732 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
733 {
734 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
735 clone_info->cache_filename);
736 return(MagickFalse);
737 }
738 count=WritePixelCacheRegion(clone_info,clone_info->offset,
739 clone_info->length,(unsigned char *) cache_info->pixels);
740 (void) ClosePixelCacheOnDisk(clone_info);
741 if ((MagickSizeType) count != clone_info->length)
742 {
743 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
744 clone_info->cache_filename);
745 return(MagickFalse);
746 }
747 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000748 }
749 /*
cristy4c08aed2011-07-01 19:47:50 +0000750 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000751 */
cristy4c08aed2011-07-01 19:47:50 +0000752 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000753}
754
cristyfd24a062012-01-02 14:46:34 +0000755static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000756 CacheInfo *cache_info,ExceptionInfo *exception)
757{
cristy4c08aed2011-07-01 19:47:50 +0000758 MagickBooleanType
759 status;
cristy3ed852e2009-09-05 21:47:34 +0000760
cristy4c08aed2011-07-01 19:47:50 +0000761 MagickOffsetType
762 cache_offset,
763 clone_offset,
764 count;
765
766 register ssize_t
767 x;
768
cristyfd24a062012-01-02 14:46:34 +0000769 register unsigned char
770 *p;
771
cristy4c08aed2011-07-01 19:47:50 +0000772 size_t
cristy3ed852e2009-09-05 21:47:34 +0000773 length;
774
cristy4c08aed2011-07-01 19:47:50 +0000775 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000776 y;
777
cristy4c08aed2011-07-01 19:47:50 +0000778 unsigned char
779 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000780
cristy4c08aed2011-07-01 19:47:50 +0000781 /*
782 Clone pixel cache (unoptimized).
783 */
cristy3ed852e2009-09-05 21:47:34 +0000784 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000785 {
cristy4c08aed2011-07-01 19:47:50 +0000786 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
787 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
788 else
789 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
790 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
791 else
792 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
794 else
795 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
796 }
cristyed231572011-07-14 02:18:59 +0000797 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
798 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000799 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000800 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000801 if (blob == (unsigned char *) NULL)
802 {
803 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000804 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000805 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000806 return(MagickFalse);
807 }
cristy4c08aed2011-07-01 19:47:50 +0000808 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
809 cache_offset=0;
810 clone_offset=0;
811 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000814 {
cristy4c08aed2011-07-01 19:47:50 +0000815 blob=(unsigned char *) RelinquishMagickMemory(blob);
816 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000817 cache_info->cache_filename);
818 return(MagickFalse);
819 }
cristy4c08aed2011-07-01 19:47:50 +0000820 cache_offset=cache_info->offset;
821 }
822 if (clone_info->type == DiskCache)
823 {
cristy3dedf062011-07-02 14:07:40 +0000824 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000825 {
cristy4c08aed2011-07-01 19:47:50 +0000826 blob=(unsigned char *) RelinquishMagickMemory(blob);
827 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
828 clone_info->cache_filename);
829 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000830 }
cristy4c08aed2011-07-01 19:47:50 +0000831 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000832 }
833 /*
cristy4c08aed2011-07-01 19:47:50 +0000834 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000835 */
cristy4c08aed2011-07-01 19:47:50 +0000836 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000837 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000838 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000839 {
cristy4c08aed2011-07-01 19:47:50 +0000840 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000841 {
cristy9e0719b2011-12-29 03:45:45 +0000842 register ssize_t
843 i;
844
cristy3ed852e2009-09-05 21:47:34 +0000845 /*
cristy4c08aed2011-07-01 19:47:50 +0000846 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000847 */
cristyed231572011-07-14 02:18:59 +0000848 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000849 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000850 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000851 else
852 {
cristyfd24a062012-01-02 14:46:34 +0000853 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000854 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000855 {
cristy4c08aed2011-07-01 19:47:50 +0000856 status=MagickFalse;
857 break;
cristy3ed852e2009-09-05 21:47:34 +0000858 }
859 }
cristy4c08aed2011-07-01 19:47:50 +0000860 cache_offset+=length;
861 if ((y < (ssize_t) clone_info->rows) &&
862 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000863 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000864 {
cristy9e0719b2011-12-29 03:45:45 +0000865 PixelChannel
866 channel;
867
868 PixelTrait
869 traits;
870
871 ssize_t
872 offset;
873
cristy4c08aed2011-07-01 19:47:50 +0000874 /*
cristy3b8fe922011-12-29 18:56:23 +0000875 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000876 */
cristy9e0719b2011-12-29 03:45:45 +0000877 channel=clone_info->channel_map[i].channel;
878 traits=cache_info->channel_map[channel].traits;
879 if (traits == UndefinedPixelTrait)
880 {
cristy0f4425e2011-12-31 20:33:02 +0000881 clone_offset+=sizeof(Quantum);
882 continue;
cristy9e0719b2011-12-29 03:45:45 +0000883 }
cristy0f4425e2011-12-31 20:33:02 +0000884 offset=cache_info->channel_map[channel].offset;
885 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000886 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
887 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000888 else
889 {
cristy0f4425e2011-12-31 20:33:02 +0000890 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000891 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000892 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000893 {
cristy0f4425e2011-12-31 20:33:02 +0000894 status=MagickFalse;
895 break;
cristy4c08aed2011-07-01 19:47:50 +0000896 }
897 }
cristy9e0719b2011-12-29 03:45:45 +0000898 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000899 }
900 }
cristyac245f82012-05-05 17:13:57 +0000901 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000902 {
903 /*
904 Set remaining columns as undefined.
905 */
cristy888e6132012-04-23 19:54:54 +0000906 length=clone_info->number_channels*sizeof(Quantum);
907 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
908 for ( ; x < (ssize_t) clone_info->columns; x++)
909 {
910 if (clone_info->type != DiskCache)
911 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
912 blob,length);
913 else
914 {
915 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
916 if ((MagickSizeType) count != length)
917 {
918 status=MagickFalse;
919 break;
cristye04362f2012-04-23 15:33:05 +0000920 }
cristy888e6132012-04-23 19:54:54 +0000921 }
922 clone_offset+=length;
923 }
cristye04362f2012-04-23 15:33:05 +0000924 }
cristy4c08aed2011-07-01 19:47:50 +0000925 }
cristyed231572011-07-14 02:18:59 +0000926 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000927 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
928 for ( ; y < (ssize_t) clone_info->rows; y++)
929 {
930 /*
cristy9e0719b2011-12-29 03:45:45 +0000931 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000932 */
933 for (x=0; x < (ssize_t) clone_info->columns; x++)
934 {
935 if (clone_info->type != DiskCache)
936 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
937 length);
938 else
939 {
940 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
941 if ((MagickSizeType) count != length)
942 {
943 status=MagickFalse;
944 break;
945 }
946 }
947 clone_offset+=length;
948 }
949 }
cristy9e0719b2011-12-29 03:45:45 +0000950 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000951 (clone_info->metacontent_extent != 0))
952 {
953 /*
954 Clone metacontent.
955 */
956 for (y=0; y < (ssize_t) cache_info->rows; y++)
957 {
958 for (x=0; x < (ssize_t) cache_info->columns; x++)
959 {
960 /*
961 Read a set of metacontent.
962 */
963 length=cache_info->metacontent_extent;
964 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000965 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000966 else
967 {
cristyfd24a062012-01-02 14:46:34 +0000968 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000969 if ((MagickSizeType) count != length)
970 {
971 status=MagickFalse;
972 break;
973 }
974 }
975 cache_offset+=length;
976 if ((y < (ssize_t) clone_info->rows) &&
977 (x < (ssize_t) clone_info->columns))
978 {
979 /*
980 Write a set of metacontent.
981 */
982 length=clone_info->metacontent_extent;
983 if (clone_info->type != DiskCache)
984 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000985 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000986 else
987 {
cristyfd24a062012-01-02 14:46:34 +0000988 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000989 if ((MagickSizeType) count != length)
990 {
991 status=MagickFalse;
992 break;
993 }
994 }
995 clone_offset+=length;
996 }
997 }
998 length=clone_info->metacontent_extent;
999 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1000 for ( ; x < (ssize_t) clone_info->columns; x++)
1001 {
1002 /*
cristy9e0719b2011-12-29 03:45:45 +00001003 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001004 */
1005 if (clone_info->type != DiskCache)
1006 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1007 blob,length);
1008 else
1009 {
cristy208b1002011-08-07 18:51:50 +00001010 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001011 if ((MagickSizeType) count != length)
1012 {
1013 status=MagickFalse;
1014 break;
1015 }
1016 }
1017 clone_offset+=length;
1018 }
1019 }
cristyac245f82012-05-05 17:13:57 +00001020 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001021 {
cristye04362f2012-04-23 15:33:05 +00001022 /*
1023 Set remaining rows as undefined.
1024 */
cristy888e6132012-04-23 19:54:54 +00001025 length=clone_info->metacontent_extent;
1026 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1027 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001028 {
cristy888e6132012-04-23 19:54:54 +00001029 for (x=0; x < (ssize_t) clone_info->columns; x++)
1030 {
1031 if (clone_info->type != DiskCache)
1032 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1033 blob,length);
1034 else
1035 {
1036 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1037 blob);
1038 if ((MagickSizeType) count != length)
1039 {
1040 status=MagickFalse;
1041 break;
1042 }
1043 }
1044 clone_offset+=length;
1045 }
cristye04362f2012-04-23 15:33:05 +00001046 }
cristy4c08aed2011-07-01 19:47:50 +00001047 }
cristy4c08aed2011-07-01 19:47:50 +00001048 }
1049 if (clone_info->type == DiskCache)
1050 (void) ClosePixelCacheOnDisk(clone_info);
1051 if (cache_info->type == DiskCache)
1052 (void) ClosePixelCacheOnDisk(cache_info);
1053 blob=(unsigned char *) RelinquishMagickMemory(blob);
1054 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001055}
1056
1057static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1058 CacheInfo *cache_info,ExceptionInfo *exception)
1059{
cristy3dfccb22011-12-28 21:47:20 +00001060 PixelChannelMap
1061 *p,
1062 *q;
1063
cristy5a7fbfb2010-11-06 16:10:59 +00001064 if (cache_info->type == PingCache)
1065 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001066 p=cache_info->channel_map;
1067 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001068 if ((cache_info->columns == clone_info->columns) &&
1069 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001070 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001071 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001072 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001073 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1074 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001075}
1076
1077/*
1078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079% %
1080% %
1081% %
1082+ C l o n e P i x e l C a c h e M e t h o d s %
1083% %
1084% %
1085% %
1086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087%
1088% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1089% another.
1090%
1091% The format of the ClonePixelCacheMethods() method is:
1092%
1093% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1094%
1095% A description of each parameter follows:
1096%
1097% o clone: Specifies a pointer to a Cache structure.
1098%
1099% o cache: the pixel cache.
1100%
1101*/
cristya6577ff2011-09-02 19:54:26 +00001102MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001103{
1104 CacheInfo
1105 *cache_info,
1106 *source_info;
1107
1108 assert(clone != (Cache) NULL);
1109 source_info=(CacheInfo *) clone;
1110 assert(source_info->signature == MagickSignature);
1111 if (source_info->debug != MagickFalse)
1112 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1113 source_info->filename);
1114 assert(cache != (Cache) NULL);
1115 cache_info=(CacheInfo *) cache;
1116 assert(cache_info->signature == MagickSignature);
1117 source_info->methods=cache_info->methods;
1118}
1119
1120/*
1121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122% %
1123% %
1124% %
1125+ D e s t r o y I m a g e P i x e l C a c h e %
1126% %
1127% %
1128% %
1129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1130%
1131% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1132%
1133% The format of the DestroyImagePixelCache() method is:
1134%
1135% void DestroyImagePixelCache(Image *image)
1136%
1137% A description of each parameter follows:
1138%
1139% o image: the image.
1140%
1141*/
1142static void DestroyImagePixelCache(Image *image)
1143{
1144 assert(image != (Image *) NULL);
1145 assert(image->signature == MagickSignature);
1146 if (image->debug != MagickFalse)
1147 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1148 if (image->cache == (void *) NULL)
1149 return;
1150 image->cache=DestroyPixelCache(image->cache);
1151}
1152
1153/*
1154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1155% %
1156% %
1157% %
1158+ D e s t r o y I m a g e P i x e l s %
1159% %
1160% %
1161% %
1162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1163%
1164% DestroyImagePixels() deallocates memory associated with the pixel cache.
1165%
1166% The format of the DestroyImagePixels() method is:
1167%
1168% void DestroyImagePixels(Image *image)
1169%
1170% A description of each parameter follows:
1171%
1172% o image: the image.
1173%
1174*/
1175MagickExport void DestroyImagePixels(Image *image)
1176{
1177 CacheInfo
1178 *cache_info;
1179
1180 assert(image != (const Image *) NULL);
1181 assert(image->signature == MagickSignature);
1182 if (image->debug != MagickFalse)
1183 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1184 assert(image->cache != (Cache) NULL);
1185 cache_info=(CacheInfo *) image->cache;
1186 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001187 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1188 {
1189 cache_info->methods.destroy_pixel_handler(image);
1190 return;
1191 }
cristy2036f5c2010-09-19 21:18:17 +00001192 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001193}
1194
1195/*
1196%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197% %
1198% %
1199% %
1200+ D e s t r o y P i x e l C a c h e %
1201% %
1202% %
1203% %
1204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205%
1206% DestroyPixelCache() deallocates memory associated with the pixel cache.
1207%
1208% The format of the DestroyPixelCache() method is:
1209%
1210% Cache DestroyPixelCache(Cache cache)
1211%
1212% A description of each parameter follows:
1213%
1214% o cache: the pixel cache.
1215%
1216*/
1217
1218static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1219{
1220 switch (cache_info->type)
1221 {
1222 case MemoryCache:
1223 {
1224 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001225 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001226 cache_info->pixels);
1227 else
cristy4c08aed2011-07-01 19:47:50 +00001228 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001229 (size_t) cache_info->length);
1230 RelinquishMagickResource(MemoryResource,cache_info->length);
1231 break;
1232 }
1233 case MapCache:
1234 {
cristy4c08aed2011-07-01 19:47:50 +00001235 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001236 cache_info->length);
1237 RelinquishMagickResource(MapResource,cache_info->length);
1238 }
1239 case DiskCache:
1240 {
1241 if (cache_info->file != -1)
1242 (void) ClosePixelCacheOnDisk(cache_info);
1243 RelinquishMagickResource(DiskResource,cache_info->length);
1244 break;
1245 }
1246 default:
1247 break;
1248 }
1249 cache_info->type=UndefinedCache;
1250 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001251 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001252}
1253
cristya6577ff2011-09-02 19:54:26 +00001254MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001255{
1256 CacheInfo
1257 *cache_info;
1258
cristy3ed852e2009-09-05 21:47:34 +00001259 assert(cache != (Cache) NULL);
1260 cache_info=(CacheInfo *) cache;
1261 assert(cache_info->signature == MagickSignature);
1262 if (cache_info->debug != MagickFalse)
1263 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1264 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001265 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001266 cache_info->reference_count--;
1267 if (cache_info->reference_count != 0)
1268 {
cristyf84a1932010-01-03 18:00:18 +00001269 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001270 return((Cache) NULL);
1271 }
cristyf84a1932010-01-03 18:00:18 +00001272 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001273 if (cache_info->debug != MagickFalse)
1274 {
1275 char
1276 message[MaxTextExtent];
1277
cristyb51dff52011-05-19 16:55:47 +00001278 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001279 cache_info->filename);
1280 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1281 }
cristyc2e1bdd2009-09-10 23:43:34 +00001282 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1283 (cache_info->type != DiskCache)))
1284 RelinquishPixelCachePixels(cache_info);
1285 else
1286 {
1287 RelinquishPixelCachePixels(cache_info);
1288 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1289 }
cristy3ed852e2009-09-05 21:47:34 +00001290 *cache_info->cache_filename='\0';
1291 if (cache_info->nexus_info != (NexusInfo **) NULL)
1292 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1293 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001294 if (cache_info->random_info != (RandomInfo *) NULL)
1295 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001296 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1297 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1298 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1299 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001300 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001301 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001302 cache=(Cache) NULL;
1303 return(cache);
1304}
1305
1306/*
1307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308% %
1309% %
1310% %
1311+ D e s t r o y P i x e l C a c h e N e x u s %
1312% %
1313% %
1314% %
1315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1316%
1317% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1318%
1319% The format of the DestroyPixelCacheNexus() method is:
1320%
1321% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001322% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001323%
1324% A description of each parameter follows:
1325%
1326% o nexus_info: the nexus to destroy.
1327%
1328% o number_threads: the number of nexus threads.
1329%
1330*/
1331
1332static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1333{
1334 if (nexus_info->mapped == MagickFalse)
cristy64c3edf2012-04-13 18:50:13 +00001335 (void) RelinquishMagickMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001336 else
1337 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001338 nexus_info->cache=(Quantum *) NULL;
1339 nexus_info->pixels=(Quantum *) NULL;
1340 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001341 nexus_info->length=0;
1342 nexus_info->mapped=MagickFalse;
1343}
1344
cristya6577ff2011-09-02 19:54:26 +00001345MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001346 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001347{
cristybb503372010-05-27 20:51:26 +00001348 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001349 i;
1350
1351 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001352 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001353 {
cristy4c08aed2011-07-01 19:47:50 +00001354 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001355 RelinquishCacheNexusPixels(nexus_info[i]);
1356 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001357 }
cristye5f87c82012-02-14 12:44:17 +00001358 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001359 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001360 return(nexus_info);
1361}
1362
1363/*
1364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365% %
1366% %
1367% %
cristy4c08aed2011-07-01 19:47:50 +00001368% G e t A u t h e n t i c M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00001369% %
1370% %
1371% %
1372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1373%
cristy4c08aed2011-07-01 19:47:50 +00001374% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1375% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1376% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001377%
cristy4c08aed2011-07-01 19:47:50 +00001378% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001379%
cristy4c08aed2011-07-01 19:47:50 +00001380% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001381%
1382% A description of each parameter follows:
1383%
1384% o image: the image.
1385%
1386*/
cristy4c08aed2011-07-01 19:47:50 +00001387MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001388{
1389 CacheInfo
1390 *cache_info;
1391
cristy5c9e6f22010-09-17 17:31:01 +00001392 const int
1393 id = GetOpenMPThreadId();
1394
cristy4c08aed2011-07-01 19:47:50 +00001395 void
1396 *metacontent;
1397
cristye7cc7cf2010-09-21 13:26:47 +00001398 assert(image != (const Image *) NULL);
1399 assert(image->signature == MagickSignature);
1400 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001401 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001402 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001403 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1404 (GetAuthenticMetacontentFromHandler) NULL)
1405 {
1406 metacontent=cache_info->methods.
1407 get_authentic_metacontent_from_handler(image);
1408 return(metacontent);
1409 }
cristy6ebe97c2010-07-03 01:17:28 +00001410 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001411 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1412 cache_info->nexus_info[id]);
1413 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001414}
1415
1416/*
1417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1418% %
1419% %
1420% %
cristy4c08aed2011-07-01 19:47:50 +00001421+ G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00001422% %
1423% %
1424% %
1425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426%
cristy4c08aed2011-07-01 19:47:50 +00001427% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1428% with the last call to QueueAuthenticPixelsCache() or
1429% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001430%
cristy4c08aed2011-07-01 19:47:50 +00001431% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001432%
cristy4c08aed2011-07-01 19:47:50 +00001433% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001434%
1435% A description of each parameter follows:
1436%
1437% o image: the image.
1438%
1439*/
cristy4c08aed2011-07-01 19:47:50 +00001440static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001441{
1442 CacheInfo
1443 *cache_info;
1444
cristy2036f5c2010-09-19 21:18:17 +00001445 const int
1446 id = GetOpenMPThreadId();
1447
cristy4c08aed2011-07-01 19:47:50 +00001448 void
1449 *metacontent;
1450
cristy3ed852e2009-09-05 21:47:34 +00001451 assert(image != (const Image *) NULL);
1452 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001453 assert(image->cache != (Cache) NULL);
1454 cache_info=(CacheInfo *) image->cache;
1455 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001456 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001457 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1458 cache_info->nexus_info[id]);
1459 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001460}
1461
1462/*
1463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1464% %
1465% %
1466% %
1467+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1468% %
1469% %
1470% %
1471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1472%
1473% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1474% disk pixel cache as defined by the geometry parameters. A pointer to the
1475% pixels is returned if the pixels are transferred, otherwise a NULL is
1476% returned.
1477%
1478% The format of the GetAuthenticPixelCacheNexus() method is:
1479%
cristy4c08aed2011-07-01 19:47:50 +00001480% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001481% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001482% NexusInfo *nexus_info,ExceptionInfo *exception)
1483%
1484% A description of each parameter follows:
1485%
1486% o image: the image.
1487%
1488% o x,y,columns,rows: These values define the perimeter of a region of
1489% pixels.
1490%
1491% o nexus_info: the cache nexus to return.
1492%
1493% o exception: return any errors or warnings in this structure.
1494%
1495*/
1496
cristy4c08aed2011-07-01 19:47:50 +00001497static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001498 NexusInfo *nexus_info)
1499{
cristy4c08aed2011-07-01 19:47:50 +00001500 MagickBooleanType
1501 status;
1502
cristy3ed852e2009-09-05 21:47:34 +00001503 MagickOffsetType
1504 offset;
1505
cristy73724512010-04-12 14:43:14 +00001506 if (cache_info->type == PingCache)
1507 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001508 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1509 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001510 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001511 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001512 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001513}
1514
cristya6577ff2011-09-02 19:54:26 +00001515MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001516 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001517 NexusInfo *nexus_info,ExceptionInfo *exception)
1518{
1519 CacheInfo
1520 *cache_info;
1521
cristy4c08aed2011-07-01 19:47:50 +00001522 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001523 *q;
cristy3ed852e2009-09-05 21:47:34 +00001524
1525 /*
1526 Transfer pixels from the cache.
1527 */
1528 assert(image != (Image *) NULL);
1529 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001530 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1531 exception);
cristyacd2ed22011-08-30 01:44:23 +00001532 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001533 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001534 cache_info=(CacheInfo *) image->cache;
1535 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001536 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001537 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001538 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001539 return((Quantum *) NULL);
1540 if (cache_info->metacontent_extent != 0)
1541 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1542 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001543 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001544}
1545
1546/*
1547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1548% %
1549% %
1550% %
1551+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1552% %
1553% %
1554% %
1555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556%
1557% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1558% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1559%
1560% The format of the GetAuthenticPixelsFromCache() method is:
1561%
cristy4c08aed2011-07-01 19:47:50 +00001562% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001563%
1564% A description of each parameter follows:
1565%
1566% o image: the image.
1567%
1568*/
cristy4c08aed2011-07-01 19:47:50 +00001569static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001570{
1571 CacheInfo
1572 *cache_info;
1573
cristy5c9e6f22010-09-17 17:31:01 +00001574 const int
1575 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001576
cristye7cc7cf2010-09-21 13:26:47 +00001577 assert(image != (const Image *) NULL);
1578 assert(image->signature == MagickSignature);
1579 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001580 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001581 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001582 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001583 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001584}
1585
1586/*
1587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588% %
1589% %
1590% %
1591% G e t A u t h e n t i c P i x e l Q u e u e %
1592% %
1593% %
1594% %
1595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596%
cristy4c08aed2011-07-01 19:47:50 +00001597% GetAuthenticPixelQueue() returns the authentic pixels associated
1598% corresponding with the last call to QueueAuthenticPixels() or
1599% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001600%
1601% The format of the GetAuthenticPixelQueue() method is:
1602%
cristy4c08aed2011-07-01 19:47:50 +00001603% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001604%
1605% A description of each parameter follows:
1606%
1607% o image: the image.
1608%
1609*/
cristy4c08aed2011-07-01 19:47:50 +00001610MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001611{
1612 CacheInfo
1613 *cache_info;
1614
cristy2036f5c2010-09-19 21:18:17 +00001615 const int
1616 id = GetOpenMPThreadId();
1617
cristy3ed852e2009-09-05 21:47:34 +00001618 assert(image != (const Image *) NULL);
1619 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001620 assert(image->cache != (Cache) NULL);
1621 cache_info=(CacheInfo *) image->cache;
1622 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001623 if (cache_info->methods.get_authentic_pixels_from_handler !=
1624 (GetAuthenticPixelsFromHandler) NULL)
1625 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001626 assert(id < (int) cache_info->number_threads);
1627 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001628}
1629
1630/*
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632% %
1633% %
1634% %
1635% G e t A u t h e n t i c P i x e l s %
1636% %
1637% %
cristy4c08aed2011-07-01 19:47:50 +00001638% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001639%
1640% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001641% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001642% representing the region is returned, otherwise NULL is returned.
1643%
1644% The returned pointer may point to a temporary working copy of the pixels
1645% or it may point to the original pixels in memory. Performance is maximized
1646% if the selected region is part of one row, or one or more full rows, since
1647% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001648% if the image is in memory, or in a memory-mapped file. The returned pointer
1649% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001650%
1651% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001652% Quantum. If the image has corresponding metacontent,call
1653% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1654% meta-content corresponding to the region. Once the Quantum array has
1655% been updated, the changes must be saved back to the underlying image using
1656% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001657%
1658% The format of the GetAuthenticPixels() method is:
1659%
cristy4c08aed2011-07-01 19:47:50 +00001660% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001661% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001662% ExceptionInfo *exception)
1663%
1664% A description of each parameter follows:
1665%
1666% o image: the image.
1667%
1668% o x,y,columns,rows: These values define the perimeter of a region of
1669% pixels.
1670%
1671% o exception: return any errors or warnings in this structure.
1672%
1673*/
cristy4c08aed2011-07-01 19:47:50 +00001674MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001675 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001676 ExceptionInfo *exception)
1677{
1678 CacheInfo
1679 *cache_info;
1680
cristy2036f5c2010-09-19 21:18:17 +00001681 const int
1682 id = GetOpenMPThreadId();
1683
cristy4c08aed2011-07-01 19:47:50 +00001684 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001685 *q;
cristy4c08aed2011-07-01 19:47:50 +00001686
cristy3ed852e2009-09-05 21:47:34 +00001687 assert(image != (Image *) NULL);
1688 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001689 assert(image->cache != (Cache) NULL);
1690 cache_info=(CacheInfo *) image->cache;
1691 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001692 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001693 (GetAuthenticPixelsHandler) NULL)
1694 {
cristyacd2ed22011-08-30 01:44:23 +00001695 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1696 exception);
1697 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001698 }
cristy2036f5c2010-09-19 21:18:17 +00001699 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001700 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001701 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001702 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001703}
1704
1705/*
1706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1707% %
1708% %
1709% %
1710+ G e t A u t h e n t i c P i x e l s C a c h e %
1711% %
1712% %
1713% %
1714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1715%
1716% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1717% as defined by the geometry parameters. A pointer to the pixels is returned
1718% if the pixels are transferred, otherwise a NULL is returned.
1719%
1720% The format of the GetAuthenticPixelsCache() method is:
1721%
cristy4c08aed2011-07-01 19:47:50 +00001722% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001723% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001724% ExceptionInfo *exception)
1725%
1726% A description of each parameter follows:
1727%
1728% o image: the image.
1729%
1730% o x,y,columns,rows: These values define the perimeter of a region of
1731% pixels.
1732%
1733% o exception: return any errors or warnings in this structure.
1734%
1735*/
cristy4c08aed2011-07-01 19:47:50 +00001736static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001737 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001738 ExceptionInfo *exception)
1739{
1740 CacheInfo
1741 *cache_info;
1742
cristy5c9e6f22010-09-17 17:31:01 +00001743 const int
1744 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001745
cristy4c08aed2011-07-01 19:47:50 +00001746 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001747 *q;
cristy4c08aed2011-07-01 19:47:50 +00001748
cristye7cc7cf2010-09-21 13:26:47 +00001749 assert(image != (const Image *) NULL);
1750 assert(image->signature == MagickSignature);
1751 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001752 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001753 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001754 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001755 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001756 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001757 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001758 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001759 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001760}
1761
1762/*
1763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1764% %
1765% %
1766% %
1767+ G e t I m a g e E x t e n t %
1768% %
1769% %
1770% %
1771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1772%
cristy4c08aed2011-07-01 19:47:50 +00001773% GetImageExtent() returns the extent of the pixels associated corresponding
1774% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001775%
1776% The format of the GetImageExtent() method is:
1777%
1778% MagickSizeType GetImageExtent(const Image *image)
1779%
1780% A description of each parameter follows:
1781%
1782% o image: the image.
1783%
1784*/
1785MagickExport MagickSizeType GetImageExtent(const Image *image)
1786{
1787 CacheInfo
1788 *cache_info;
1789
cristy5c9e6f22010-09-17 17:31:01 +00001790 const int
1791 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001792
cristy3ed852e2009-09-05 21:47:34 +00001793 assert(image != (Image *) NULL);
1794 assert(image->signature == MagickSignature);
1795 if (image->debug != MagickFalse)
1796 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1797 assert(image->cache != (Cache) NULL);
1798 cache_info=(CacheInfo *) image->cache;
1799 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001800 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001801 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001802}
1803
1804/*
1805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1806% %
1807% %
1808% %
1809+ G e t I m a g e P i x e l C a c h e %
1810% %
1811% %
1812% %
1813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1814%
1815% GetImagePixelCache() ensures that there is only a single reference to the
1816% pixel cache to be modified, updating the provided cache pointer to point to
1817% a clone of the original pixel cache if necessary.
1818%
1819% The format of the GetImagePixelCache method is:
1820%
1821% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1822% ExceptionInfo *exception)
1823%
1824% A description of each parameter follows:
1825%
1826% o image: the image.
1827%
1828% o clone: any value other than MagickFalse clones the cache pixels.
1829%
1830% o exception: return any errors or warnings in this structure.
1831%
1832*/
cristyaf894d72011-08-06 23:03:10 +00001833
cristy3ed852e2009-09-05 21:47:34 +00001834static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1835{
1836 CacheInfo
1837 *cache_info;
1838
cristy9e0719b2011-12-29 03:45:45 +00001839 PixelChannelMap
1840 *p,
1841 *q;
1842
cristy3ed852e2009-09-05 21:47:34 +00001843 /*
1844 Does the image match the pixel cache morphology?
1845 */
1846 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001847 p=image->channel_map;
1848 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001849 if ((image->storage_class != cache_info->storage_class) ||
1850 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001851 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001852 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001853 (image->columns != cache_info->columns) ||
1854 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001855 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001856 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001857 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001858 (cache_info->nexus_info == (NexusInfo **) NULL) ||
cristyac245f82012-05-05 17:13:57 +00001859 (cache_info->number_threads < (size_t) GetMagickResourceLimit(ThreadResource)))
cristy3ed852e2009-09-05 21:47:34 +00001860 return(MagickFalse);
1861 return(MagickTrue);
1862}
1863
cristycd01fae2011-08-06 23:52:42 +00001864static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1865 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001866{
1867 CacheInfo
1868 *cache_info;
1869
cristy3ed852e2009-09-05 21:47:34 +00001870 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001871 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001872 status;
1873
cristy50a10922010-02-15 18:35:25 +00001874 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001875 cpu_throttle = 0,
1876 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001877 time_limit = 0;
1878
cristy1ea34962010-07-01 19:49:21 +00001879 static time_t
cristy208b1002011-08-07 18:51:50 +00001880 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001881
cristyc4f9f132010-03-04 18:50:01 +00001882 status=MagickTrue;
1883 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001884 if (cpu_throttle == 0)
1885 {
1886 char
1887 *limit;
1888
1889 /*
1890 Set CPU throttle in milleseconds.
1891 */
1892 cpu_throttle=MagickResourceInfinity;
1893 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1894 if (limit == (char *) NULL)
1895 limit=GetPolicyValue("throttle");
1896 if (limit != (char *) NULL)
1897 {
1898 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1899 limit=DestroyString(limit);
1900 }
1901 }
1902 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1903 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001904 if (time_limit == 0)
1905 {
cristy6ebe97c2010-07-03 01:17:28 +00001906 /*
1907 Set the exire time in seconds.
1908 */
cristy1ea34962010-07-01 19:49:21 +00001909 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001910 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001911 }
1912 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001913 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001914 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001915 assert(image->cache != (Cache) NULL);
1916 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001917 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001918 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001919 {
cristyceb55ee2010-11-06 16:05:49 +00001920 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001921 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001922 {
cristyceb55ee2010-11-06 16:05:49 +00001923 Image
1924 clone_image;
1925
1926 CacheInfo
1927 *clone_info;
1928
1929 /*
1930 Clone pixel cache.
1931 */
1932 clone_image=(*image);
1933 clone_image.semaphore=AllocateSemaphoreInfo();
1934 clone_image.reference_count=1;
1935 clone_image.cache=ClonePixelCache(cache_info);
1936 clone_info=(CacheInfo *) clone_image.cache;
1937 status=OpenPixelCache(&clone_image,IOMode,exception);
1938 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001939 {
cristy5a7fbfb2010-11-06 16:10:59 +00001940 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001941 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001942 if (status != MagickFalse)
1943 {
cristy979bf772011-08-08 00:04:15 +00001944 if (cache_info->mode == ReadMode)
1945 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001946 destroy=MagickTrue;
1947 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001948 }
1949 }
cristyceb55ee2010-11-06 16:05:49 +00001950 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001951 }
cristyceb55ee2010-11-06 16:05:49 +00001952 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001953 }
cristy4320e0e2009-09-10 15:00:08 +00001954 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001955 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001956 if (status != MagickFalse)
1957 {
1958 /*
1959 Ensure the image matches the pixel cache morphology.
1960 */
1961 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001962 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001963 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001964 {
1965 status=OpenPixelCache(image,IOMode,exception);
1966 cache_info=(CacheInfo *) image->cache;
1967 if (cache_info->type == DiskCache)
1968 (void) ClosePixelCacheOnDisk(cache_info);
1969 }
cristy3ed852e2009-09-05 21:47:34 +00001970 }
cristyf84a1932010-01-03 18:00:18 +00001971 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001972 if (status == MagickFalse)
1973 return((Cache) NULL);
1974 return(image->cache);
1975}
1976
1977/*
1978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1979% %
1980% %
1981% %
1982% G e t O n e A u t h e n t i c P i x e l %
1983% %
1984% %
1985% %
1986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1987%
1988% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1989% location. The image background color is returned if an error occurs.
1990%
1991% The format of the GetOneAuthenticPixel() method is:
1992%
cristybb503372010-05-27 20:51:26 +00001993% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00001994% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001995%
1996% A description of each parameter follows:
1997%
1998% o image: the image.
1999%
2000% o x,y: These values define the location of the pixel to return.
2001%
2002% o pixel: return a pixel at the specified (x,y) location.
2003%
2004% o exception: return any errors or warnings in this structure.
2005%
2006*/
cristyacbbb7c2010-06-30 18:56:48 +00002007MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002008 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002009{
2010 CacheInfo
2011 *cache_info;
2012
cristy4c08aed2011-07-01 19:47:50 +00002013 register Quantum
2014 *q;
cristy2036f5c2010-09-19 21:18:17 +00002015
cristy2ed42f62011-10-02 19:49:57 +00002016 register ssize_t
2017 i;
2018
cristy3ed852e2009-09-05 21:47:34 +00002019 assert(image != (Image *) NULL);
2020 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002021 assert(image->cache != (Cache) NULL);
2022 cache_info=(CacheInfo *) image->cache;
2023 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002024 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002025 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2026 (GetOneAuthenticPixelFromHandler) NULL)
2027 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2028 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002029 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2030 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002031 {
cristy9e0719b2011-12-29 03:45:45 +00002032 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2033 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2034 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2035 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2036 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002037 return(MagickFalse);
2038 }
2039 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2040 {
2041 PixelChannel
2042 channel;
2043
cristye2a912b2011-12-05 20:02:07 +00002044 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002045 pixel[channel]=q[i];
2046 }
cristy2036f5c2010-09-19 21:18:17 +00002047 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002048}
2049
2050/*
2051%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2052% %
2053% %
2054% %
2055+ 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 %
2056% %
2057% %
2058% %
2059%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2060%
2061% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2062% location. The image background color is returned if an error occurs.
2063%
2064% The format of the GetOneAuthenticPixelFromCache() method is:
2065%
2066% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002067% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002068% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002069%
2070% A description of each parameter follows:
2071%
2072% o image: the image.
2073%
2074% o x,y: These values define the location of the pixel to return.
2075%
2076% o pixel: return a pixel at the specified (x,y) location.
2077%
2078% o exception: return any errors or warnings in this structure.
2079%
2080*/
2081static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002082 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002083{
cristy098f78c2010-09-23 17:28:44 +00002084 CacheInfo
2085 *cache_info;
2086
2087 const int
2088 id = GetOpenMPThreadId();
2089
cristy4c08aed2011-07-01 19:47:50 +00002090 register Quantum
2091 *q;
cristy3ed852e2009-09-05 21:47:34 +00002092
cristy2ed42f62011-10-02 19:49:57 +00002093 register ssize_t
2094 i;
2095
cristy0158a4b2010-09-20 13:59:45 +00002096 assert(image != (const Image *) NULL);
2097 assert(image->signature == MagickSignature);
2098 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002099 cache_info=(CacheInfo *) image->cache;
2100 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002101 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002102 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002103 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2104 exception);
2105 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002106 {
cristy9e0719b2011-12-29 03:45:45 +00002107 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2108 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2109 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2110 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2111 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002112 return(MagickFalse);
2113 }
2114 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2115 {
2116 PixelChannel
2117 channel;
2118
cristye2a912b2011-12-05 20:02:07 +00002119 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002120 pixel[channel]=q[i];
2121 }
cristy3ed852e2009-09-05 21:47:34 +00002122 return(MagickTrue);
2123}
2124
2125/*
2126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2127% %
2128% %
2129% %
cristy3ed852e2009-09-05 21:47:34 +00002130% G e t O n e V i r t u a l P i x e l %
2131% %
2132% %
2133% %
2134%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2135%
2136% GetOneVirtualPixel() returns a single virtual pixel at the specified
2137% (x,y) location. The image background color is returned if an error occurs.
2138% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2139%
2140% The format of the GetOneVirtualPixel() method is:
2141%
cristybb503372010-05-27 20:51:26 +00002142% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002143% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002144%
2145% A description of each parameter follows:
2146%
2147% o image: the image.
2148%
2149% o x,y: These values define the location of the pixel to return.
2150%
2151% o pixel: return a pixel at the specified (x,y) location.
2152%
2153% o exception: return any errors or warnings in this structure.
2154%
2155*/
2156MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002157 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002158{
cristy3ed852e2009-09-05 21:47:34 +00002159 CacheInfo
2160 *cache_info;
2161
cristy0158a4b2010-09-20 13:59:45 +00002162 const int
2163 id = GetOpenMPThreadId();
2164
cristy4c08aed2011-07-01 19:47:50 +00002165 const Quantum
2166 *p;
cristy2036f5c2010-09-19 21:18:17 +00002167
cristy2ed42f62011-10-02 19:49:57 +00002168 register ssize_t
2169 i;
2170
cristy3ed852e2009-09-05 21:47:34 +00002171 assert(image != (const Image *) NULL);
2172 assert(image->signature == MagickSignature);
2173 assert(image->cache != (Cache) NULL);
2174 cache_info=(CacheInfo *) image->cache;
2175 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002176 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002177 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2178 (GetOneVirtualPixelFromHandler) NULL)
2179 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2180 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002181 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002182 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002183 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002184 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002185 {
cristy9e0719b2011-12-29 03:45:45 +00002186 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2187 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2188 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2189 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2190 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002191 return(MagickFalse);
2192 }
2193 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2194 {
2195 PixelChannel
2196 channel;
2197
cristye2a912b2011-12-05 20:02:07 +00002198 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002199 pixel[channel]=p[i];
2200 }
cristy2036f5c2010-09-19 21:18:17 +00002201 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002202}
2203
2204/*
2205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2206% %
2207% %
2208% %
2209+ 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 %
2210% %
2211% %
2212% %
2213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2214%
2215% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2216% specified (x,y) location. The image background color is returned if an
2217% error occurs.
2218%
2219% The format of the GetOneVirtualPixelFromCache() method is:
2220%
2221% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002222% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002223% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002224%
2225% A description of each parameter follows:
2226%
2227% o image: the image.
2228%
2229% o virtual_pixel_method: the virtual pixel method.
2230%
2231% o x,y: These values define the location of the pixel to return.
2232%
2233% o pixel: return a pixel at the specified (x,y) location.
2234%
2235% o exception: return any errors or warnings in this structure.
2236%
2237*/
2238static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002239 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002240 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002241{
cristy0158a4b2010-09-20 13:59:45 +00002242 CacheInfo
2243 *cache_info;
2244
2245 const int
2246 id = GetOpenMPThreadId();
2247
cristy4c08aed2011-07-01 19:47:50 +00002248 const Quantum
2249 *p;
cristy3ed852e2009-09-05 21:47:34 +00002250
cristy2ed42f62011-10-02 19:49:57 +00002251 register ssize_t
2252 i;
2253
cristye7cc7cf2010-09-21 13:26:47 +00002254 assert(image != (const Image *) NULL);
2255 assert(image->signature == MagickSignature);
2256 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002257 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002258 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002259 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002260 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002261 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002262 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002263 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002264 {
cristy9e0719b2011-12-29 03:45:45 +00002265 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2266 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2267 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2268 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2269 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002270 return(MagickFalse);
2271 }
2272 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2273 {
2274 PixelChannel
2275 channel;
2276
cristye2a912b2011-12-05 20:02:07 +00002277 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002278 pixel[channel]=p[i];
2279 }
cristy3ed852e2009-09-05 21:47:34 +00002280 return(MagickTrue);
2281}
2282
2283/*
2284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285% %
2286% %
2287% %
cristy3aa93752011-12-18 15:54:24 +00002288% G e t O n e V i r t u a l P i x e l I n f o %
2289% %
2290% %
2291% %
2292%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2293%
2294% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2295% location. The image background color is returned if an error occurs. If
2296% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2297%
2298% The format of the GetOneVirtualPixelInfo() method is:
2299%
2300% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2301% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2302% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2303%
2304% A description of each parameter follows:
2305%
2306% o image: the image.
2307%
2308% o virtual_pixel_method: the virtual pixel method.
2309%
2310% o x,y: these values define the location of the pixel to return.
2311%
2312% o pixel: return a pixel at the specified (x,y) location.
2313%
2314% o exception: return any errors or warnings in this structure.
2315%
2316*/
2317MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2318 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2319 PixelInfo *pixel,ExceptionInfo *exception)
2320{
2321 CacheInfo
2322 *cache_info;
2323
2324 const int
2325 id = GetOpenMPThreadId();
2326
2327 register const Quantum
2328 *p;
2329
2330 assert(image != (const Image *) NULL);
2331 assert(image->signature == MagickSignature);
2332 assert(image->cache != (Cache) NULL);
2333 cache_info=(CacheInfo *) image->cache;
2334 assert(cache_info->signature == MagickSignature);
2335 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002336 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002337 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2338 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002339 if (p == (const Quantum *) NULL)
2340 return(MagickFalse);
2341 GetPixelInfoPixel(image,p,pixel);
2342 return(MagickTrue);
2343}
2344
2345/*
2346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2347% %
2348% %
2349% %
cristy3ed852e2009-09-05 21:47:34 +00002350+ G e t P i x e l C a c h e C o l o r s p a c e %
2351% %
2352% %
2353% %
2354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2355%
2356% GetPixelCacheColorspace() returns the class type of the pixel cache.
2357%
2358% The format of the GetPixelCacheColorspace() method is:
2359%
2360% Colorspace GetPixelCacheColorspace(Cache cache)
2361%
2362% A description of each parameter follows:
2363%
2364% o cache: the pixel cache.
2365%
2366*/
cristya6577ff2011-09-02 19:54:26 +00002367MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002368{
2369 CacheInfo
2370 *cache_info;
2371
2372 assert(cache != (Cache) NULL);
2373 cache_info=(CacheInfo *) cache;
2374 assert(cache_info->signature == MagickSignature);
2375 if (cache_info->debug != MagickFalse)
2376 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2377 cache_info->filename);
2378 return(cache_info->colorspace);
2379}
2380
2381/*
2382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2383% %
2384% %
2385% %
2386+ G e t P i x e l C a c h e M e t h o d s %
2387% %
2388% %
2389% %
2390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2391%
2392% GetPixelCacheMethods() initializes the CacheMethods structure.
2393%
2394% The format of the GetPixelCacheMethods() method is:
2395%
2396% void GetPixelCacheMethods(CacheMethods *cache_methods)
2397%
2398% A description of each parameter follows:
2399%
2400% o cache_methods: Specifies a pointer to a CacheMethods structure.
2401%
2402*/
cristya6577ff2011-09-02 19:54:26 +00002403MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002404{
2405 assert(cache_methods != (CacheMethods *) NULL);
2406 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2407 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2408 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002409 cache_methods->get_virtual_metacontent_from_handler=
2410 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002411 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2412 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002413 cache_methods->get_authentic_metacontent_from_handler=
2414 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002415 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2416 cache_methods->get_one_authentic_pixel_from_handler=
2417 GetOneAuthenticPixelFromCache;
2418 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2419 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2420 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2421}
2422
2423/*
2424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2425% %
2426% %
2427% %
2428+ G e t P i x e l C a c h e N e x u s E x t e n t %
2429% %
2430% %
2431% %
2432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2433%
cristy4c08aed2011-07-01 19:47:50 +00002434% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2435% corresponding with the last call to SetPixelCacheNexusPixels() or
2436% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002437%
2438% The format of the GetPixelCacheNexusExtent() method is:
2439%
2440% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2441% NexusInfo *nexus_info)
2442%
2443% A description of each parameter follows:
2444%
2445% o nexus_info: the nexus info.
2446%
2447*/
cristya6577ff2011-09-02 19:54:26 +00002448MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002449 NexusInfo *nexus_info)
2450{
2451 CacheInfo
2452 *cache_info;
2453
2454 MagickSizeType
2455 extent;
2456
cristy9f027d12011-09-21 01:17:17 +00002457 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002458 cache_info=(CacheInfo *) cache;
2459 assert(cache_info->signature == MagickSignature);
2460 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2461 if (extent == 0)
2462 return((MagickSizeType) cache_info->columns*cache_info->rows);
2463 return(extent);
2464}
2465
2466/*
2467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2468% %
2469% %
2470% %
cristy4c08aed2011-07-01 19:47:50 +00002471+ 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 +00002472% %
2473% %
2474% %
2475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2476%
cristy4c08aed2011-07-01 19:47:50 +00002477% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2478% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002479%
cristy4c08aed2011-07-01 19:47:50 +00002480% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002481%
cristy4c08aed2011-07-01 19:47:50 +00002482% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002483% NexusInfo *nexus_info)
2484%
2485% A description of each parameter follows:
2486%
2487% o cache: the pixel cache.
2488%
cristy4c08aed2011-07-01 19:47:50 +00002489% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002490%
2491*/
cristya6577ff2011-09-02 19:54:26 +00002492MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002493 NexusInfo *nexus_info)
2494{
2495 CacheInfo
2496 *cache_info;
2497
cristy9f027d12011-09-21 01:17:17 +00002498 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002499 cache_info=(CacheInfo *) cache;
2500 assert(cache_info->signature == MagickSignature);
2501 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002502 return((void *) NULL);
2503 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002504}
2505
2506/*
2507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508% %
2509% %
2510% %
2511+ G e t P i x e l C a c h e N e x u s P i x e l s %
2512% %
2513% %
2514% %
2515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2516%
2517% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2518% cache nexus.
2519%
2520% The format of the GetPixelCacheNexusPixels() method is:
2521%
cristy4c08aed2011-07-01 19:47:50 +00002522% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002523% NexusInfo *nexus_info)
2524%
2525% A description of each parameter follows:
2526%
2527% o cache: the pixel cache.
2528%
2529% o nexus_info: the cache nexus to return the pixels.
2530%
2531*/
cristya6577ff2011-09-02 19:54:26 +00002532MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002533 NexusInfo *nexus_info)
2534{
2535 CacheInfo
2536 *cache_info;
2537
cristy9f027d12011-09-21 01:17:17 +00002538 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002539 cache_info=(CacheInfo *) cache;
2540 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002541 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002542 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002543 return(nexus_info->pixels);
2544}
2545
2546/*
2547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548% %
2549% %
2550% %
cristy056ba772010-01-02 23:33:54 +00002551+ G e t P i x e l C a c h e P i x e l s %
2552% %
2553% %
2554% %
2555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2556%
2557% GetPixelCachePixels() returns the pixels associated with the specified image.
2558%
2559% The format of the GetPixelCachePixels() method is:
2560%
cristyf84a1932010-01-03 18:00:18 +00002561% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2562% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002563%
2564% A description of each parameter follows:
2565%
2566% o image: the image.
2567%
2568% o length: the pixel cache length.
2569%
cristyf84a1932010-01-03 18:00:18 +00002570% o exception: return any errors or warnings in this structure.
2571%
cristy056ba772010-01-02 23:33:54 +00002572*/
cristyd1dd6e42011-09-04 01:46:08 +00002573MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002574 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002575{
2576 CacheInfo
2577 *cache_info;
2578
2579 assert(image != (const Image *) NULL);
2580 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002581 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002582 assert(length != (MagickSizeType *) NULL);
2583 assert(exception != (ExceptionInfo *) NULL);
2584 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002585 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002586 assert(cache_info->signature == MagickSignature);
2587 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002588 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002589 return((void *) NULL);
2590 *length=cache_info->length;
2591 return((void *) cache_info->pixels);
2592}
2593
2594/*
2595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2596% %
2597% %
2598% %
cristyb32b90a2009-09-07 21:45:48 +00002599+ 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 +00002600% %
2601% %
2602% %
2603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2604%
2605% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2606%
2607% The format of the GetPixelCacheStorageClass() method is:
2608%
2609% ClassType GetPixelCacheStorageClass(Cache cache)
2610%
2611% A description of each parameter follows:
2612%
2613% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2614%
2615% o cache: the pixel cache.
2616%
2617*/
cristya6577ff2011-09-02 19:54:26 +00002618MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002619{
2620 CacheInfo
2621 *cache_info;
2622
2623 assert(cache != (Cache) NULL);
2624 cache_info=(CacheInfo *) cache;
2625 assert(cache_info->signature == MagickSignature);
2626 if (cache_info->debug != MagickFalse)
2627 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2628 cache_info->filename);
2629 return(cache_info->storage_class);
2630}
2631
2632/*
2633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2634% %
2635% %
2636% %
cristyb32b90a2009-09-07 21:45:48 +00002637+ G e t P i x e l C a c h e T i l e S i z e %
2638% %
2639% %
2640% %
2641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2642%
2643% GetPixelCacheTileSize() returns the pixel cache tile size.
2644%
2645% The format of the GetPixelCacheTileSize() method is:
2646%
cristybb503372010-05-27 20:51:26 +00002647% void GetPixelCacheTileSize(const Image *image,size_t *width,
2648% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002649%
2650% A description of each parameter follows:
2651%
2652% o image: the image.
2653%
2654% o width: the optimize cache tile width in pixels.
2655%
2656% o height: the optimize cache tile height in pixels.
2657%
2658*/
cristya6577ff2011-09-02 19:54:26 +00002659MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002660 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002661{
cristy4c08aed2011-07-01 19:47:50 +00002662 CacheInfo
2663 *cache_info;
2664
cristyb32b90a2009-09-07 21:45:48 +00002665 assert(image != (Image *) NULL);
2666 assert(image->signature == MagickSignature);
2667 if (image->debug != MagickFalse)
2668 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002669 cache_info=(CacheInfo *) image->cache;
2670 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002671 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002672 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002673 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002674 *height=(*width);
2675}
2676
2677/*
2678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2679% %
2680% %
2681% %
2682+ G e t P i x e l C a c h e T y p e %
2683% %
2684% %
2685% %
2686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2687%
2688% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2689%
2690% The format of the GetPixelCacheType() method is:
2691%
2692% CacheType GetPixelCacheType(const Image *image)
2693%
2694% A description of each parameter follows:
2695%
2696% o image: the image.
2697%
2698*/
cristya6577ff2011-09-02 19:54:26 +00002699MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002700{
2701 CacheInfo
2702 *cache_info;
2703
2704 assert(image != (Image *) NULL);
2705 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002706 assert(image->cache != (Cache) NULL);
2707 cache_info=(CacheInfo *) image->cache;
2708 assert(cache_info->signature == MagickSignature);
2709 return(cache_info->type);
2710}
2711
2712/*
2713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714% %
2715% %
2716% %
cristy3ed852e2009-09-05 21:47:34 +00002717+ 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 %
2718% %
2719% %
2720% %
2721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722%
2723% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2724% pixel cache. A virtual pixel is any pixel access that is outside the
2725% boundaries of the image cache.
2726%
2727% The format of the GetPixelCacheVirtualMethod() method is:
2728%
2729% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2730%
2731% A description of each parameter follows:
2732%
2733% o image: the image.
2734%
2735*/
cristyd1dd6e42011-09-04 01:46:08 +00002736MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002737{
2738 CacheInfo
2739 *cache_info;
2740
2741 assert(image != (Image *) NULL);
2742 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002743 assert(image->cache != (Cache) NULL);
2744 cache_info=(CacheInfo *) image->cache;
2745 assert(cache_info->signature == MagickSignature);
2746 return(cache_info->virtual_pixel_method);
2747}
2748
2749/*
2750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2751% %
2752% %
2753% %
cristy4c08aed2011-07-01 19:47:50 +00002754+ 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 +00002755% %
2756% %
2757% %
2758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2759%
cristy4c08aed2011-07-01 19:47:50 +00002760% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2761% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002762%
cristy4c08aed2011-07-01 19:47:50 +00002763% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002764%
cristy4c08aed2011-07-01 19:47:50 +00002765% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002766%
2767% A description of each parameter follows:
2768%
2769% o image: the image.
2770%
2771*/
cristy4c08aed2011-07-01 19:47:50 +00002772static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002773{
2774 CacheInfo
2775 *cache_info;
2776
cristy5c9e6f22010-09-17 17:31:01 +00002777 const int
2778 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002779
cristy4c08aed2011-07-01 19:47:50 +00002780 const void
2781 *metacontent;
2782
cristye7cc7cf2010-09-21 13:26:47 +00002783 assert(image != (const Image *) NULL);
2784 assert(image->signature == MagickSignature);
2785 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002786 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002787 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002788 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002789 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2790 cache_info->nexus_info[id]);
2791 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002792}
2793
2794/*
2795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796% %
2797% %
2798% %
cristy4c08aed2011-07-01 19:47:50 +00002799+ 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 +00002800% %
2801% %
2802% %
2803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804%
cristy4c08aed2011-07-01 19:47:50 +00002805% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2806% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002807%
cristy4c08aed2011-07-01 19:47:50 +00002808% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002809%
cristy4c08aed2011-07-01 19:47:50 +00002810% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002811% NexusInfo *nexus_info)
2812%
2813% A description of each parameter follows:
2814%
2815% o cache: the pixel cache.
2816%
cristy4c08aed2011-07-01 19:47:50 +00002817% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002818%
2819*/
cristya6577ff2011-09-02 19:54:26 +00002820MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002821 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002822{
2823 CacheInfo
2824 *cache_info;
2825
cristye7cc7cf2010-09-21 13:26:47 +00002826 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002827 cache_info=(CacheInfo *) cache;
2828 assert(cache_info->signature == MagickSignature);
2829 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002830 return((void *) NULL);
2831 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002832}
2833
2834/*
2835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2836% %
2837% %
2838% %
cristy4c08aed2011-07-01 19:47:50 +00002839% 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 +00002840% %
2841% %
2842% %
2843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2844%
cristy4c08aed2011-07-01 19:47:50 +00002845% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2846% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2847% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002848%
cristy4c08aed2011-07-01 19:47:50 +00002849% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002850%
cristy4c08aed2011-07-01 19:47:50 +00002851% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002852%
2853% A description of each parameter follows:
2854%
2855% o image: the image.
2856%
2857*/
cristy4c08aed2011-07-01 19:47:50 +00002858MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002859{
2860 CacheInfo
2861 *cache_info;
2862
cristy2036f5c2010-09-19 21:18:17 +00002863 const int
2864 id = GetOpenMPThreadId();
2865
cristy4c08aed2011-07-01 19:47:50 +00002866 const void
2867 *metacontent;
2868
cristy3ed852e2009-09-05 21:47:34 +00002869 assert(image != (const Image *) NULL);
2870 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002871 assert(image->cache != (Cache) NULL);
2872 cache_info=(CacheInfo *) image->cache;
2873 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002874 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2875 if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
2876 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002877 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002878 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2879 cache_info->nexus_info[id]);
2880 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002881}
2882
2883/*
2884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885% %
2886% %
2887% %
2888+ 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 %
2889% %
2890% %
2891% %
2892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2893%
2894% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2895% pixel cache as defined by the geometry parameters. A pointer to the pixels
2896% is returned if the pixels are transferred, otherwise a NULL is returned.
2897%
2898% The format of the GetVirtualPixelsFromNexus() method is:
2899%
cristy4c08aed2011-07-01 19:47:50 +00002900% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002901% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002902% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2903% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002904%
2905% A description of each parameter follows:
2906%
2907% o image: the image.
2908%
2909% o virtual_pixel_method: the virtual pixel method.
2910%
2911% o x,y,columns,rows: These values define the perimeter of a region of
2912% pixels.
2913%
2914% o nexus_info: the cache nexus to acquire.
2915%
2916% o exception: return any errors or warnings in this structure.
2917%
2918*/
2919
cristybb503372010-05-27 20:51:26 +00002920static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002921 DitherMatrix[64] =
2922 {
2923 0, 48, 12, 60, 3, 51, 15, 63,
2924 32, 16, 44, 28, 35, 19, 47, 31,
2925 8, 56, 4, 52, 11, 59, 7, 55,
2926 40, 24, 36, 20, 43, 27, 39, 23,
2927 2, 50, 14, 62, 1, 49, 13, 61,
2928 34, 18, 46, 30, 33, 17, 45, 29,
2929 10, 58, 6, 54, 9, 57, 5, 53,
2930 42, 26, 38, 22, 41, 25, 37, 21
2931 };
2932
cristybb503372010-05-27 20:51:26 +00002933static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002934{
cristybb503372010-05-27 20:51:26 +00002935 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002936 index;
2937
2938 index=x+DitherMatrix[x & 0x07]-32L;
2939 if (index < 0L)
2940 return(0L);
cristybb503372010-05-27 20:51:26 +00002941 if (index >= (ssize_t) columns)
2942 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002943 return(index);
2944}
2945
cristybb503372010-05-27 20:51:26 +00002946static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002947{
cristybb503372010-05-27 20:51:26 +00002948 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002949 index;
2950
2951 index=y+DitherMatrix[y & 0x07]-32L;
2952 if (index < 0L)
2953 return(0L);
cristybb503372010-05-27 20:51:26 +00002954 if (index >= (ssize_t) rows)
2955 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002956 return(index);
2957}
2958
cristybb503372010-05-27 20:51:26 +00002959static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002960{
2961 if (x < 0L)
2962 return(0L);
cristybb503372010-05-27 20:51:26 +00002963 if (x >= (ssize_t) columns)
2964 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002965 return(x);
2966}
2967
cristybb503372010-05-27 20:51:26 +00002968static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002969{
2970 if (y < 0L)
2971 return(0L);
cristybb503372010-05-27 20:51:26 +00002972 if (y >= (ssize_t) rows)
2973 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002974 return(y);
2975}
2976
cristybb503372010-05-27 20:51:26 +00002977static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002978{
cristybb503372010-05-27 20:51:26 +00002979 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002980}
2981
cristybb503372010-05-27 20:51:26 +00002982static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002983{
cristybb503372010-05-27 20:51:26 +00002984 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002985}
2986
cristybb503372010-05-27 20:51:26 +00002987static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2988 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002989{
2990 MagickModulo
2991 modulo;
2992
cristy6162bb42011-07-18 11:34:09 +00002993 /*
2994 Compute the remainder of dividing offset by extent. It returns not only
2995 the quotient (tile the offset falls in) but also the positive remainer
2996 within that tile such that 0 <= remainder < extent. This method is
2997 essentially a ldiv() using a floored modulo division rather than the
2998 normal default truncated modulo division.
2999 */
cristybb503372010-05-27 20:51:26 +00003000 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003001 if (offset < 0L)
3002 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003003 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003004 return(modulo);
3005}
3006
cristya6577ff2011-09-02 19:54:26 +00003007MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003008 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3009 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003010 ExceptionInfo *exception)
3011{
3012 CacheInfo
3013 *cache_info;
3014
3015 MagickOffsetType
3016 offset;
3017
3018 MagickSizeType
3019 length,
3020 number_pixels;
3021
3022 NexusInfo
3023 **virtual_nexus;
3024
cristy4c08aed2011-07-01 19:47:50 +00003025 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003026 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003027 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003028
3029 RectangleInfo
3030 region;
3031
cristy4c08aed2011-07-01 19:47:50 +00003032 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003033 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003034
cristy4c08aed2011-07-01 19:47:50 +00003035 register const void
3036 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003037
cristy4c08aed2011-07-01 19:47:50 +00003038 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003039 *restrict q;
3040
cristybb503372010-05-27 20:51:26 +00003041 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003042 i,
3043 u;
cristy3ed852e2009-09-05 21:47:34 +00003044
cristy4c08aed2011-07-01 19:47:50 +00003045 register unsigned char
3046 *restrict s;
3047
cristy105ba3c2011-07-18 02:28:38 +00003048 ssize_t
3049 v;
3050
cristy4c08aed2011-07-01 19:47:50 +00003051 void
cristy105ba3c2011-07-18 02:28:38 +00003052 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003053
cristy3ed852e2009-09-05 21:47:34 +00003054 /*
3055 Acquire pixels.
3056 */
cristye7cc7cf2010-09-21 13:26:47 +00003057 assert(image != (const Image *) NULL);
3058 assert(image->signature == MagickSignature);
3059 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003060 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003061 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003062 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003063 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003064 region.x=x;
3065 region.y=y;
3066 region.width=columns;
3067 region.height=rows;
3068 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003069 if (pixels == (Quantum *) NULL)
3070 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003071 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003072 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3073 nexus_info->region.x;
3074 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3075 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003076 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3077 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003078 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3079 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003080 {
3081 MagickBooleanType
3082 status;
3083
3084 /*
3085 Pixel request is inside cache extents.
3086 */
cristy4c08aed2011-07-01 19:47:50 +00003087 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003088 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003089 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3090 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003091 return((const Quantum *) NULL);
3092 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003093 {
cristy4c08aed2011-07-01 19:47:50 +00003094 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003095 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003096 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003097 }
cristyacd2ed22011-08-30 01:44:23 +00003098 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003099 }
3100 /*
3101 Pixel request is outside cache extents.
3102 */
cristy4c08aed2011-07-01 19:47:50 +00003103 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003104 virtual_nexus=AcquirePixelCacheNexus(1);
3105 if (virtual_nexus == (NexusInfo **) NULL)
3106 {
cristy4c08aed2011-07-01 19:47:50 +00003107 if (virtual_nexus != (NexusInfo **) NULL)
3108 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003109 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003110 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003111 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003112 }
cristy105ba3c2011-07-18 02:28:38 +00003113 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3114 sizeof(*virtual_pixel));
3115 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003116 switch (virtual_pixel_method)
3117 {
cristy4c08aed2011-07-01 19:47:50 +00003118 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003119 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003121 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003122 case MaskVirtualPixelMethod:
3123 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003124 case EdgeVirtualPixelMethod:
3125 case CheckerTileVirtualPixelMethod:
3126 case HorizontalTileVirtualPixelMethod:
3127 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003128 {
cristy4c08aed2011-07-01 19:47:50 +00003129 if (cache_info->metacontent_extent != 0)
3130 {
cristy6162bb42011-07-18 11:34:09 +00003131 /*
3132 Acquire a metacontent buffer.
3133 */
cristya64b85d2011-09-14 01:02:31 +00003134 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003135 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003136 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003137 {
cristy4c08aed2011-07-01 19:47:50 +00003138 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3139 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003140 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003141 return((const Quantum *) NULL);
3142 }
cristy105ba3c2011-07-18 02:28:38 +00003143 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003144 cache_info->metacontent_extent);
3145 }
3146 switch (virtual_pixel_method)
3147 {
3148 case BlackVirtualPixelMethod:
3149 {
cristy30301712011-07-18 15:06:51 +00003150 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3151 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003152 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3153 break;
3154 }
3155 case GrayVirtualPixelMethod:
3156 {
cristy30301712011-07-18 15:06:51 +00003157 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003158 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3159 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003160 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3161 break;
3162 }
3163 case TransparentVirtualPixelMethod:
3164 {
cristy30301712011-07-18 15:06:51 +00003165 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3166 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003167 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3168 break;
3169 }
3170 case MaskVirtualPixelMethod:
3171 case WhiteVirtualPixelMethod:
3172 {
cristy30301712011-07-18 15:06:51 +00003173 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3174 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003175 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3176 break;
3177 }
3178 default:
3179 {
cristy9e0719b2011-12-29 03:45:45 +00003180 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3181 virtual_pixel);
3182 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3183 virtual_pixel);
3184 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3185 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003186 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3187 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003188 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3189 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003190 break;
3191 }
3192 }
cristy3ed852e2009-09-05 21:47:34 +00003193 break;
3194 }
3195 default:
cristy3ed852e2009-09-05 21:47:34 +00003196 break;
cristy3ed852e2009-09-05 21:47:34 +00003197 }
cristybb503372010-05-27 20:51:26 +00003198 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003199 {
cristybb503372010-05-27 20:51:26 +00003200 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003201 {
3202 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003203 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003204 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3205 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003206 {
3207 MagickModulo
3208 x_modulo,
3209 y_modulo;
3210
3211 /*
3212 Transfer a single pixel.
3213 */
3214 length=(MagickSizeType) 1;
3215 switch (virtual_pixel_method)
3216 {
cristy3ed852e2009-09-05 21:47:34 +00003217 default:
3218 {
3219 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003220 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003221 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003222 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003223 break;
3224 }
3225 case RandomVirtualPixelMethod:
3226 {
3227 if (cache_info->random_info == (RandomInfo *) NULL)
3228 cache_info->random_info=AcquireRandomInfo();
3229 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003230 RandomX(cache_info->random_info,cache_info->columns),
3231 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003232 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003233 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003234 break;
3235 }
3236 case DitherVirtualPixelMethod:
3237 {
3238 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003239 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003240 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003241 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003242 break;
3243 }
3244 case TileVirtualPixelMethod:
3245 {
3246 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3247 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3248 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003249 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003250 exception);
cristy4c08aed2011-07-01 19:47:50 +00003251 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003252 break;
3253 }
3254 case MirrorVirtualPixelMethod:
3255 {
3256 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3257 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003258 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003259 x_modulo.remainder-1L;
3260 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3261 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003262 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003263 y_modulo.remainder-1L;
3264 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003265 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003266 exception);
cristy4c08aed2011-07-01 19:47:50 +00003267 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003268 break;
3269 }
3270 case HorizontalTileEdgeVirtualPixelMethod:
3271 {
3272 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3273 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003274 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003275 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003276 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003277 break;
3278 }
3279 case VerticalTileEdgeVirtualPixelMethod:
3280 {
3281 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3282 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003283 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003284 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003285 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3286 break;
3287 }
3288 case BackgroundVirtualPixelMethod:
3289 case BlackVirtualPixelMethod:
3290 case GrayVirtualPixelMethod:
3291 case TransparentVirtualPixelMethod:
3292 case MaskVirtualPixelMethod:
3293 case WhiteVirtualPixelMethod:
3294 {
3295 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003296 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003297 break;
3298 }
3299 case EdgeVirtualPixelMethod:
3300 case CheckerTileVirtualPixelMethod:
3301 {
3302 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3303 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3304 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3305 {
3306 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003307 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003308 break;
3309 }
3310 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3311 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3312 exception);
3313 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3314 break;
3315 }
3316 case HorizontalTileVirtualPixelMethod:
3317 {
3318 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3319 {
3320 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003321 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003322 break;
3323 }
3324 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3325 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3326 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3327 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3328 exception);
3329 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3330 break;
3331 }
3332 case VerticalTileVirtualPixelMethod:
3333 {
3334 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3335 {
3336 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003337 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003338 break;
3339 }
3340 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3341 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3342 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3343 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3344 exception);
3345 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003346 break;
3347 }
3348 }
cristy4c08aed2011-07-01 19:47:50 +00003349 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003350 break;
cristyed231572011-07-14 02:18:59 +00003351 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003352 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003353 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003354 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003355 {
3356 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3357 s+=cache_info->metacontent_extent;
3358 }
cristy3ed852e2009-09-05 21:47:34 +00003359 continue;
3360 }
3361 /*
3362 Transfer a run of pixels.
3363 */
cristy4c08aed2011-07-01 19:47:50 +00003364 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3365 length,1UL,*virtual_nexus,exception);
3366 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003367 break;
cristy4c08aed2011-07-01 19:47:50 +00003368 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003369 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3370 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003371 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003372 {
cristy4c08aed2011-07-01 19:47:50 +00003373 (void) memcpy(s,r,(size_t) length);
3374 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003375 }
3376 }
3377 }
cristy4c08aed2011-07-01 19:47:50 +00003378 /*
3379 Free resources.
3380 */
cristy105ba3c2011-07-18 02:28:38 +00003381 if (virtual_metacontent != (void *) NULL)
3382 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003383 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3384 return(pixels);
3385}
3386
3387/*
3388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3389% %
3390% %
3391% %
3392+ G e t V i r t u a l P i x e l C a c h e %
3393% %
3394% %
3395% %
3396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3397%
3398% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3399% cache as defined by the geometry parameters. A pointer to the pixels
3400% is returned if the pixels are transferred, otherwise a NULL is returned.
3401%
3402% The format of the GetVirtualPixelCache() method is:
3403%
cristy4c08aed2011-07-01 19:47:50 +00003404% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003405% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3406% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003407% ExceptionInfo *exception)
3408%
3409% A description of each parameter follows:
3410%
3411% o image: the image.
3412%
3413% o virtual_pixel_method: the virtual pixel method.
3414%
3415% o x,y,columns,rows: These values define the perimeter of a region of
3416% pixels.
3417%
3418% o exception: return any errors or warnings in this structure.
3419%
3420*/
cristy4c08aed2011-07-01 19:47:50 +00003421static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003422 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3423 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003424{
3425 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003426 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003427
cristy5c9e6f22010-09-17 17:31:01 +00003428 const int
3429 id = GetOpenMPThreadId();
3430
cristy4c08aed2011-07-01 19:47:50 +00003431 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003432 *p;
cristy4c08aed2011-07-01 19:47:50 +00003433
cristye7cc7cf2010-09-21 13:26:47 +00003434 assert(image != (const Image *) NULL);
3435 assert(image->signature == MagickSignature);
3436 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003437 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003438 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003439 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003440 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003441 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003442 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003443}
3444
3445/*
3446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3447% %
3448% %
3449% %
3450% G e t V i r t u a l P i x e l Q u e u e %
3451% %
3452% %
3453% %
3454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3455%
cristy4c08aed2011-07-01 19:47:50 +00003456% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3457% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003458%
3459% The format of the GetVirtualPixelQueue() method is:
3460%
cristy4c08aed2011-07-01 19:47:50 +00003461% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003462%
3463% A description of each parameter follows:
3464%
3465% o image: the image.
3466%
3467*/
cristy4c08aed2011-07-01 19:47:50 +00003468MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003469{
3470 CacheInfo
3471 *cache_info;
3472
cristy2036f5c2010-09-19 21:18:17 +00003473 const int
3474 id = GetOpenMPThreadId();
3475
cristy3ed852e2009-09-05 21:47:34 +00003476 assert(image != (const Image *) NULL);
3477 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003478 assert(image->cache != (Cache) NULL);
3479 cache_info=(CacheInfo *) image->cache;
3480 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003481 if (cache_info->methods.get_virtual_pixels_handler !=
3482 (GetVirtualPixelsHandler) NULL)
3483 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003484 assert(id < (int) cache_info->number_threads);
3485 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003486}
3487
3488/*
3489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3490% %
3491% %
3492% %
3493% G e t V i r t u a l P i x e l s %
3494% %
3495% %
3496% %
3497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3498%
3499% GetVirtualPixels() returns an immutable pixel region. If the
3500% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003501% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003502% copy of the pixels or it may point to the original pixels in memory.
3503% Performance is maximized if the selected region is part of one row, or one
3504% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003505% (without a copy) if the image is in memory, or in a memory-mapped file. The
3506% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003507%
3508% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003509% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3510% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3511% access the meta-content (of type void) corresponding to the the
3512% region.
cristy3ed852e2009-09-05 21:47:34 +00003513%
3514% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3515%
3516% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3517% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3518% GetCacheViewAuthenticPixels() instead.
3519%
3520% The format of the GetVirtualPixels() method is:
3521%
cristy4c08aed2011-07-01 19:47:50 +00003522% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003523% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003524% ExceptionInfo *exception)
3525%
3526% A description of each parameter follows:
3527%
3528% o image: the image.
3529%
3530% o x,y,columns,rows: These values define the perimeter of a region of
3531% pixels.
3532%
3533% o exception: return any errors or warnings in this structure.
3534%
3535*/
cristy4c08aed2011-07-01 19:47:50 +00003536MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003537 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3538 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003539{
3540 CacheInfo
3541 *cache_info;
3542
cristy2036f5c2010-09-19 21:18:17 +00003543 const int
3544 id = GetOpenMPThreadId();
3545
cristy4c08aed2011-07-01 19:47:50 +00003546 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003547 *p;
cristy4c08aed2011-07-01 19:47:50 +00003548
cristy3ed852e2009-09-05 21:47:34 +00003549 assert(image != (const Image *) NULL);
3550 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003551 assert(image->cache != (Cache) NULL);
3552 cache_info=(CacheInfo *) image->cache;
3553 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003554 if (cache_info->methods.get_virtual_pixel_handler !=
3555 (GetVirtualPixelHandler) NULL)
3556 return(cache_info->methods.get_virtual_pixel_handler(image,
3557 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003558 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003559 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003560 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003561 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003562}
3563
3564/*
3565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3566% %
3567% %
3568% %
3569+ 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 %
3570% %
3571% %
3572% %
3573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3574%
cristy4c08aed2011-07-01 19:47:50 +00003575% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3576% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003577%
3578% The format of the GetVirtualPixelsCache() method is:
3579%
cristy4c08aed2011-07-01 19:47:50 +00003580% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003581%
3582% A description of each parameter follows:
3583%
3584% o image: the image.
3585%
3586*/
cristy4c08aed2011-07-01 19:47:50 +00003587static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003588{
3589 CacheInfo
3590 *cache_info;
3591
cristy5c9e6f22010-09-17 17:31:01 +00003592 const int
3593 id = GetOpenMPThreadId();
3594
cristye7cc7cf2010-09-21 13:26:47 +00003595 assert(image != (const Image *) NULL);
3596 assert(image->signature == MagickSignature);
3597 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003598 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003599 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003600 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003601 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003602}
3603
3604/*
3605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3606% %
3607% %
3608% %
3609+ G e t V i r t u a l P i x e l s N e x u s %
3610% %
3611% %
3612% %
3613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614%
3615% GetVirtualPixelsNexus() returns the pixels associated with the specified
3616% cache nexus.
3617%
3618% The format of the GetVirtualPixelsNexus() method is:
3619%
cristy4c08aed2011-07-01 19:47:50 +00003620% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003621% NexusInfo *nexus_info)
3622%
3623% A description of each parameter follows:
3624%
3625% o cache: the pixel cache.
3626%
3627% o nexus_info: the cache nexus to return the colormap pixels.
3628%
3629*/
cristya6577ff2011-09-02 19:54:26 +00003630MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003631 NexusInfo *nexus_info)
3632{
3633 CacheInfo
3634 *cache_info;
3635
cristye7cc7cf2010-09-21 13:26:47 +00003636 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003637 cache_info=(CacheInfo *) cache;
3638 assert(cache_info->signature == MagickSignature);
3639 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003640 return((Quantum *) NULL);
3641 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003642}
3643
3644/*
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646% %
3647% %
3648% %
cristy3ed852e2009-09-05 21:47:34 +00003649+ O p e n P i x e l C a c h e %
3650% %
3651% %
3652% %
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654%
3655% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3656% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003657% metacontent, and memory mapping the cache if it is disk based. The cache
3658% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003659%
3660% The format of the OpenPixelCache() method is:
3661%
3662% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3663% ExceptionInfo *exception)
3664%
3665% A description of each parameter follows:
3666%
3667% o image: the image.
3668%
3669% o mode: ReadMode, WriteMode, or IOMode.
3670%
3671% o exception: return any errors or warnings in this structure.
3672%
3673*/
3674
cristyd43a46b2010-01-21 02:13:41 +00003675static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003676{
3677 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003678 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003679 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003680 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003681 {
3682 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003683 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003684 cache_info->length);
3685 }
3686}
3687
3688static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3689{
3690 CacheInfo
3691 *cache_info;
3692
3693 MagickOffsetType
3694 count,
3695 extent,
3696 offset;
3697
3698 cache_info=(CacheInfo *) image->cache;
3699 if (image->debug != MagickFalse)
3700 {
3701 char
3702 format[MaxTextExtent],
3703 message[MaxTextExtent];
3704
cristyb9080c92009-12-01 20:13:26 +00003705 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003706 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003707 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003708 cache_info->cache_filename,cache_info->file,format);
3709 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3710 }
3711 if (length != (MagickSizeType) ((MagickOffsetType) length))
3712 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003713 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003714 if (extent < 0)
3715 return(MagickFalse);
3716 if ((MagickSizeType) extent >= length)
3717 return(MagickTrue);
3718 offset=(MagickOffsetType) length-1;
3719 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3720 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3721}
3722
3723static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3724 ExceptionInfo *exception)
3725{
cristy3ed852e2009-09-05 21:47:34 +00003726 CacheInfo
3727 *cache_info,
3728 source_info;
3729
cristyf3a6a9d2010-11-07 21:02:56 +00003730 char
3731 format[MaxTextExtent],
3732 message[MaxTextExtent];
3733
cristy4c08aed2011-07-01 19:47:50 +00003734 MagickBooleanType
3735 status;
3736
cristy3ed852e2009-09-05 21:47:34 +00003737 MagickSizeType
3738 length,
3739 number_pixels;
3740
cristy3ed852e2009-09-05 21:47:34 +00003741 size_t
cristye076a6e2010-08-15 19:59:43 +00003742 columns,
cristy3ed852e2009-09-05 21:47:34 +00003743 packet_size;
3744
cristye7cc7cf2010-09-21 13:26:47 +00003745 assert(image != (const Image *) NULL);
3746 assert(image->signature == MagickSignature);
3747 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003748 if (image->debug != MagickFalse)
3749 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3750 if ((image->columns == 0) || (image->rows == 0))
3751 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3752 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003753 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003754 source_info=(*cache_info);
3755 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003756 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003757 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003758 cache_info->storage_class=image->storage_class;
3759 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003760 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003761 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003762 cache_info->rows=image->rows;
3763 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003764 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003765 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003766 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3767 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003768 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003769 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003770 if (image->ping != MagickFalse)
3771 {
cristy73724512010-04-12 14:43:14 +00003772 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003773 cache_info->pixels=(Quantum *) NULL;
3774 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003775 cache_info->length=0;
3776 return(MagickTrue);
3777 }
cristy3ed852e2009-09-05 21:47:34 +00003778 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003779 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003780 if (image->metacontent_extent != 0)
3781 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003782 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003783 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003784 if (cache_info->columns != columns)
3785 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3786 image->filename);
3787 cache_info->length=length;
3788 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003789 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003790 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003791 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3792 {
3793 status=AcquireMagickResource(MemoryResource,cache_info->length);
3794 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3795 (cache_info->type == MemoryCache))
3796 {
cristyd43a46b2010-01-21 02:13:41 +00003797 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003798 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003799 cache_info->pixels=source_info.pixels;
3800 else
3801 {
3802 /*
3803 Create memory pixel cache.
3804 */
cristy4c08aed2011-07-01 19:47:50 +00003805 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003806 if (image->debug != MagickFalse)
3807 {
cristy32cacff2011-12-31 03:36:27 +00003808 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003809 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003810 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3811 cache_info->filename,cache_info->mapped != MagickFalse ?
3812 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003813 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003814 format);
cristy3ed852e2009-09-05 21:47:34 +00003815 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3816 message);
3817 }
cristy3ed852e2009-09-05 21:47:34 +00003818 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003819 cache_info->metacontent=(void *) NULL;
3820 if (cache_info->metacontent_extent != 0)
3821 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003822 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003823 if ((source_info.storage_class != UndefinedClass) &&
3824 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003825 {
cristy4c08aed2011-07-01 19:47:50 +00003826 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003827 exception);
3828 RelinquishPixelCachePixels(&source_info);
3829 }
cristy4c08aed2011-07-01 19:47:50 +00003830 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003831 }
3832 }
3833 RelinquishMagickResource(MemoryResource,cache_info->length);
3834 }
3835 /*
3836 Create pixel cache on disk.
3837 */
3838 status=AcquireMagickResource(DiskResource,cache_info->length);
3839 if (status == MagickFalse)
3840 {
3841 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003842 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003843 return(MagickFalse);
3844 }
cristy413f1302012-01-01 17:48:27 +00003845 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3846 {
3847 (void) ClosePixelCacheOnDisk(cache_info);
3848 *cache_info->cache_filename='\0';
3849 }
cristy3ed852e2009-09-05 21:47:34 +00003850 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3851 {
3852 RelinquishMagickResource(DiskResource,cache_info->length);
3853 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3854 image->filename);
3855 return(MagickFalse);
3856 }
3857 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3858 cache_info->length);
3859 if (status == MagickFalse)
3860 {
3861 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3862 image->filename);
3863 return(MagickFalse);
3864 }
cristyed231572011-07-14 02:18:59 +00003865 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003866 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003867 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003868 cache_info->type=DiskCache;
3869 else
3870 {
3871 status=AcquireMagickResource(MapResource,cache_info->length);
3872 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3873 (cache_info->type != MemoryCache))
3874 cache_info->type=DiskCache;
3875 else
3876 {
cristy4c08aed2011-07-01 19:47:50 +00003877 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003878 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003879 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003880 {
cristy3ed852e2009-09-05 21:47:34 +00003881 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003882 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003883 }
3884 else
3885 {
3886 /*
3887 Create file-backed memory-mapped pixel cache.
3888 */
cristy4c08aed2011-07-01 19:47:50 +00003889 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003890 (void) ClosePixelCacheOnDisk(cache_info);
3891 cache_info->type=MapCache;
3892 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003893 cache_info->metacontent=(void *) NULL;
3894 if (cache_info->metacontent_extent != 0)
3895 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003896 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003897 if ((source_info.storage_class != UndefinedClass) &&
3898 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003899 {
3900 status=ClonePixelCachePixels(cache_info,&source_info,
3901 exception);
3902 RelinquishPixelCachePixels(&source_info);
3903 }
3904 if (image->debug != MagickFalse)
3905 {
cristy413f1302012-01-01 17:48:27 +00003906 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003907 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003908 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003909 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003910 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003911 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003912 format);
cristy3ed852e2009-09-05 21:47:34 +00003913 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3914 message);
3915 }
cristy4c08aed2011-07-01 19:47:50 +00003916 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003917 }
3918 }
3919 RelinquishMagickResource(MapResource,cache_info->length);
3920 }
cristy4c08aed2011-07-01 19:47:50 +00003921 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003922 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003923 {
3924 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3925 RelinquishPixelCachePixels(&source_info);
3926 }
3927 if (image->debug != MagickFalse)
3928 {
cristyb9080c92009-12-01 20:13:26 +00003929 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003930 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003931 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003932 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003933 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003934 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003935 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3936 }
cristy4c08aed2011-07-01 19:47:50 +00003937 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003938}
3939
3940/*
3941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3942% %
3943% %
3944% %
3945+ P e r s i s t P i x e l C a c h e %
3946% %
3947% %
3948% %
3949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3950%
3951% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3952% persistent pixel cache is one that resides on disk and is not destroyed
3953% when the program exits.
3954%
3955% The format of the PersistPixelCache() method is:
3956%
3957% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3958% const MagickBooleanType attach,MagickOffsetType *offset,
3959% ExceptionInfo *exception)
3960%
3961% A description of each parameter follows:
3962%
3963% o image: the image.
3964%
3965% o filename: the persistent pixel cache filename.
3966%
cristyf3a6a9d2010-11-07 21:02:56 +00003967% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003968%
cristy3ed852e2009-09-05 21:47:34 +00003969% o initialize: A value other than zero initializes the persistent pixel
3970% cache.
3971%
3972% o offset: the offset in the persistent cache to store pixels.
3973%
3974% o exception: return any errors or warnings in this structure.
3975%
3976*/
3977MagickExport MagickBooleanType PersistPixelCache(Image *image,
3978 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3979 ExceptionInfo *exception)
3980{
3981 CacheInfo
3982 *cache_info,
3983 *clone_info;
3984
3985 Image
3986 clone_image;
3987
cristy3ed852e2009-09-05 21:47:34 +00003988 MagickBooleanType
3989 status;
3990
cristye076a6e2010-08-15 19:59:43 +00003991 ssize_t
3992 page_size;
3993
cristy3ed852e2009-09-05 21:47:34 +00003994 assert(image != (Image *) NULL);
3995 assert(image->signature == MagickSignature);
3996 if (image->debug != MagickFalse)
3997 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3998 assert(image->cache != (void *) NULL);
3999 assert(filename != (const char *) NULL);
4000 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004001 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004002 cache_info=(CacheInfo *) image->cache;
4003 assert(cache_info->signature == MagickSignature);
4004 if (attach != MagickFalse)
4005 {
4006 /*
cristy01b7eb02009-09-10 23:10:14 +00004007 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004008 */
4009 if (image->debug != MagickFalse)
4010 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004011 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004012 (void) CopyMagickString(cache_info->cache_filename,filename,
4013 MaxTextExtent);
4014 cache_info->type=DiskCache;
4015 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004016 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004017 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004018 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004019 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004020 }
cristy01b7eb02009-09-10 23:10:14 +00004021 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4022 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004023 {
cristyf84a1932010-01-03 18:00:18 +00004024 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004025 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004026 (cache_info->reference_count == 1))
4027 {
4028 int
4029 status;
4030
4031 /*
cristy01b7eb02009-09-10 23:10:14 +00004032 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004033 */
cristy320684d2011-09-23 14:55:47 +00004034 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004035 if (status == 0)
4036 {
4037 (void) CopyMagickString(cache_info->cache_filename,filename,
4038 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004039 *offset+=cache_info->length+page_size-(cache_info->length %
4040 page_size);
cristyf84a1932010-01-03 18:00:18 +00004041 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004042 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004043 if (image->debug != MagickFalse)
4044 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4045 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004046 return(MagickTrue);
4047 }
4048 }
cristyf84a1932010-01-03 18:00:18 +00004049 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004050 }
4051 /*
cristy01b7eb02009-09-10 23:10:14 +00004052 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004053 */
4054 clone_image=(*image);
4055 clone_info=(CacheInfo *) clone_image.cache;
4056 image->cache=ClonePixelCache(cache_info);
4057 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4058 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4059 cache_info->type=DiskCache;
4060 cache_info->offset=(*offset);
4061 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004062 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004063 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004064 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004065 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004066 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4067 return(status);
4068}
4069
4070/*
4071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4072% %
4073% %
4074% %
cristyc11dace2012-01-24 16:39:46 +00004075+ 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 +00004076% %
4077% %
4078% %
4079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4080%
cristyc11dace2012-01-24 16:39:46 +00004081% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4082% defined by the region rectangle and returns a pointer to the region. This
4083% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004084% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4085% pixels are transferred, otherwise a NULL is returned.
4086%
cristyc11dace2012-01-24 16:39:46 +00004087% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004088%
cristyc11dace2012-01-24 16:39:46 +00004089% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004090% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004091% const MagickBooleanType clone,NexusInfo *nexus_info,
4092% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004093%
4094% A description of each parameter follows:
4095%
4096% o image: the image.
4097%
4098% o x,y,columns,rows: These values define the perimeter of a region of
4099% pixels.
4100%
4101% o nexus_info: the cache nexus to set.
4102%
cristy65dbf172011-10-06 17:32:04 +00004103% o clone: clone the pixel cache.
4104%
cristy3ed852e2009-09-05 21:47:34 +00004105% o exception: return any errors or warnings in this structure.
4106%
4107*/
cristyc11dace2012-01-24 16:39:46 +00004108MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4109 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004110 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004111{
4112 CacheInfo
4113 *cache_info;
4114
4115 MagickOffsetType
4116 offset;
4117
4118 MagickSizeType
4119 number_pixels;
4120
4121 RectangleInfo
4122 region;
4123
4124 /*
4125 Validate pixel cache geometry.
4126 */
cristye7cc7cf2010-09-21 13:26:47 +00004127 assert(image != (const Image *) NULL);
4128 assert(image->signature == MagickSignature);
4129 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004130 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004131 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004132 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004133 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004134 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4135 {
4136 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004137 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004138 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004139 }
cristybb503372010-05-27 20:51:26 +00004140 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4141 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004142 {
4143 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004144 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004145 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004146 }
4147 offset=(MagickOffsetType) y*cache_info->columns+x;
4148 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004149 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004150 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4151 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4152 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004153 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004154 /*
4155 Return pixel cache.
4156 */
4157 region.x=x;
4158 region.y=y;
4159 region.width=columns;
4160 region.height=rows;
4161 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4162}
4163
4164/*
4165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4166% %
4167% %
4168% %
4169+ 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 %
4170% %
4171% %
4172% %
4173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4174%
4175% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4176% defined by the region rectangle and returns a pointer to the region. This
4177% region is subsequently transferred from the pixel cache with
4178% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4179% pixels are transferred, otherwise a NULL is returned.
4180%
4181% The format of the QueueAuthenticPixelsCache() method is:
4182%
cristy4c08aed2011-07-01 19:47:50 +00004183% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004184% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004185% ExceptionInfo *exception)
4186%
4187% A description of each parameter follows:
4188%
4189% o image: the image.
4190%
4191% o x,y,columns,rows: These values define the perimeter of a region of
4192% pixels.
4193%
4194% o exception: return any errors or warnings in this structure.
4195%
4196*/
cristy4c08aed2011-07-01 19:47:50 +00004197static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004198 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004199 ExceptionInfo *exception)
4200{
4201 CacheInfo
4202 *cache_info;
4203
cristy5c9e6f22010-09-17 17:31:01 +00004204 const int
4205 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004206
cristy4c08aed2011-07-01 19:47:50 +00004207 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004208 *q;
cristy4c08aed2011-07-01 19:47:50 +00004209
cristye7cc7cf2010-09-21 13:26:47 +00004210 assert(image != (const Image *) NULL);
4211 assert(image->signature == MagickSignature);
4212 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004213 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004214 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004215 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004216 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004217 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004218 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004219}
4220
4221/*
4222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4223% %
4224% %
4225% %
4226% Q u e u e A u t h e n t i c P i x e l s %
4227% %
4228% %
4229% %
4230%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4231%
4232% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004233% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004234% region is returned, otherwise NULL is returned. The returned pointer may
4235% point to a temporary working buffer for the pixels or it may point to the
4236% final location of the pixels in memory.
4237%
4238% Write-only access means that any existing pixel values corresponding to
4239% the region are ignored. This is useful if the initial image is being
4240% created from scratch, or if the existing pixel values are to be
4241% completely replaced without need to refer to their pre-existing values.
4242% The application is free to read and write the pixel buffer returned by
4243% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4244% initialize the pixel array values. Initializing pixel array values is the
4245% application's responsibility.
4246%
4247% Performance is maximized if the selected region is part of one row, or
4248% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004249% pixels in-place (without a copy) if the image is in memory, or in a
4250% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004251% by the user.
4252%
4253% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004254% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4255% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4256% obtain the meta-content (of type void) corresponding to the region.
4257% Once the Quantum (and/or Quantum) array has been updated, the
4258% changes must be saved back to the underlying image using
4259% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004260%
4261% The format of the QueueAuthenticPixels() method is:
4262%
cristy4c08aed2011-07-01 19:47:50 +00004263% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004264% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004265% ExceptionInfo *exception)
4266%
4267% A description of each parameter follows:
4268%
4269% o image: the image.
4270%
4271% o x,y,columns,rows: These values define the perimeter of a region of
4272% pixels.
4273%
4274% o exception: return any errors or warnings in this structure.
4275%
4276*/
cristy4c08aed2011-07-01 19:47:50 +00004277MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004278 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004279 ExceptionInfo *exception)
4280{
4281 CacheInfo
4282 *cache_info;
4283
cristy2036f5c2010-09-19 21:18:17 +00004284 const int
4285 id = GetOpenMPThreadId();
4286
cristy4c08aed2011-07-01 19:47:50 +00004287 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004288 *q;
cristy4c08aed2011-07-01 19:47:50 +00004289
cristy3ed852e2009-09-05 21:47:34 +00004290 assert(image != (Image *) NULL);
4291 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004292 assert(image->cache != (Cache) NULL);
4293 cache_info=(CacheInfo *) image->cache;
4294 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004295 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004296 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004297 {
cristyc36c8822012-02-14 14:02:36 +00004298 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4299 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004300 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004301 }
cristy2036f5c2010-09-19 21:18:17 +00004302 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004303 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004304 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004305 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004306}
4307
4308/*
4309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4310% %
4311% %
4312% %
cristy4c08aed2011-07-01 19:47:50 +00004313+ 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 +00004314% %
4315% %
4316% %
4317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4318%
cristy4c08aed2011-07-01 19:47:50 +00004319% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004320% the pixel cache.
4321%
cristy4c08aed2011-07-01 19:47:50 +00004322% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004323%
cristy4c08aed2011-07-01 19:47:50 +00004324% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004325% NexusInfo *nexus_info,ExceptionInfo *exception)
4326%
4327% A description of each parameter follows:
4328%
4329% o cache_info: the pixel cache.
4330%
cristy4c08aed2011-07-01 19:47:50 +00004331% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004332%
4333% o exception: return any errors or warnings in this structure.
4334%
4335*/
cristy4c08aed2011-07-01 19:47:50 +00004336static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004337 NexusInfo *nexus_info,ExceptionInfo *exception)
4338{
4339 MagickOffsetType
4340 count,
4341 offset;
4342
4343 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004344 extent,
4345 length;
cristy3ed852e2009-09-05 21:47:34 +00004346
cristybb503372010-05-27 20:51:26 +00004347 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004348 y;
4349
cristy4c08aed2011-07-01 19:47:50 +00004350 register unsigned char
4351 *restrict q;
4352
cristybb503372010-05-27 20:51:26 +00004353 size_t
cristy3ed852e2009-09-05 21:47:34 +00004354 rows;
4355
cristy4c08aed2011-07-01 19:47:50 +00004356 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004357 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004358 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004359 return(MagickTrue);
4360 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4361 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004362 length=(MagickSizeType) nexus_info->region.width*
4363 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004364 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004365 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004366 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004367 switch (cache_info->type)
4368 {
4369 case MemoryCache:
4370 case MapCache:
4371 {
cristy4c08aed2011-07-01 19:47:50 +00004372 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004373 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004374
4375 /*
cristy4c08aed2011-07-01 19:47:50 +00004376 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004377 */
cristydd341db2010-03-04 19:06:38 +00004378 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004379 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004380 {
cristy48078b12010-09-23 17:11:01 +00004381 length=extent;
cristydd341db2010-03-04 19:06:38 +00004382 rows=1UL;
4383 }
cristy4c08aed2011-07-01 19:47:50 +00004384 p=(unsigned char *) cache_info->metacontent+offset*
4385 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004386 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004387 {
cristy8f036fe2010-09-18 02:02:00 +00004388 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004389 p+=cache_info->metacontent_extent*cache_info->columns;
4390 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004391 }
4392 break;
4393 }
4394 case DiskCache:
4395 {
4396 /*
cristy4c08aed2011-07-01 19:47:50 +00004397 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004398 */
4399 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4400 {
4401 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4402 cache_info->cache_filename);
4403 return(MagickFalse);
4404 }
cristydd341db2010-03-04 19:06:38 +00004405 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004406 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004407 {
cristy48078b12010-09-23 17:11:01 +00004408 length=extent;
cristydd341db2010-03-04 19:06:38 +00004409 rows=1UL;
4410 }
cristy48078b12010-09-23 17:11:01 +00004411 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004412 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004413 {
cristy48078b12010-09-23 17:11:01 +00004414 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004415 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004416 cache_info->metacontent_extent,length,(unsigned char *) q);
4417 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004418 break;
4419 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004420 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004421 }
cristyc11dace2012-01-24 16:39:46 +00004422 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4423 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004424 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004425 {
4426 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4427 cache_info->cache_filename);
4428 return(MagickFalse);
4429 }
4430 break;
4431 }
4432 default:
4433 break;
4434 }
4435 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004436 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004437 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004438 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004439 nexus_info->region.width,(double) nexus_info->region.height,(double)
4440 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004441 return(MagickTrue);
4442}
4443
4444/*
4445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4446% %
4447% %
4448% %
4449+ R e a d P i x e l C a c h e P i x e l s %
4450% %
4451% %
4452% %
4453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4454%
4455% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4456% cache.
4457%
4458% The format of the ReadPixelCachePixels() method is:
4459%
4460% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4461% NexusInfo *nexus_info,ExceptionInfo *exception)
4462%
4463% A description of each parameter follows:
4464%
4465% o cache_info: the pixel cache.
4466%
4467% o nexus_info: the cache nexus to read the pixels.
4468%
4469% o exception: return any errors or warnings in this structure.
4470%
4471*/
4472static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4473 NexusInfo *nexus_info,ExceptionInfo *exception)
4474{
4475 MagickOffsetType
4476 count,
4477 offset;
4478
4479 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004480 extent,
4481 length;
cristy3ed852e2009-09-05 21:47:34 +00004482
cristy4c08aed2011-07-01 19:47:50 +00004483 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004484 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004485
cristye076a6e2010-08-15 19:59:43 +00004486 register ssize_t
4487 y;
4488
cristybb503372010-05-27 20:51:26 +00004489 size_t
cristy3ed852e2009-09-05 21:47:34 +00004490 rows;
4491
cristy4c08aed2011-07-01 19:47:50 +00004492 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004493 return(MagickTrue);
4494 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4495 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004496 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004497 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004498 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004499 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004500 q=nexus_info->pixels;
4501 switch (cache_info->type)
4502 {
4503 case MemoryCache:
4504 case MapCache:
4505 {
cristy4c08aed2011-07-01 19:47:50 +00004506 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004507 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004508
4509 /*
4510 Read pixels from memory.
4511 */
cristydd341db2010-03-04 19:06:38 +00004512 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004513 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004514 {
cristy48078b12010-09-23 17:11:01 +00004515 length=extent;
cristydd341db2010-03-04 19:06:38 +00004516 rows=1UL;
4517 }
cristyed231572011-07-14 02:18:59 +00004518 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004519 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004520 {
cristy8f036fe2010-09-18 02:02:00 +00004521 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004522 p+=cache_info->number_channels*cache_info->columns;
4523 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004524 }
4525 break;
4526 }
4527 case DiskCache:
4528 {
4529 /*
4530 Read pixels from disk.
4531 */
4532 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4533 {
4534 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4535 cache_info->cache_filename);
4536 return(MagickFalse);
4537 }
cristydd341db2010-03-04 19:06:38 +00004538 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004539 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004540 {
cristy48078b12010-09-23 17:11:01 +00004541 length=extent;
cristydd341db2010-03-04 19:06:38 +00004542 rows=1UL;
4543 }
cristybb503372010-05-27 20:51:26 +00004544 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004545 {
4546 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004547 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004548 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004549 break;
4550 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004551 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004552 }
cristyc11dace2012-01-24 16:39:46 +00004553 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4554 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004555 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004556 {
4557 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4558 cache_info->cache_filename);
4559 return(MagickFalse);
4560 }
4561 break;
4562 }
4563 default:
4564 break;
4565 }
4566 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004567 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004568 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004569 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004570 nexus_info->region.width,(double) nexus_info->region.height,(double)
4571 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004572 return(MagickTrue);
4573}
4574
4575/*
4576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4577% %
4578% %
4579% %
4580+ R e f e r e n c e P i x e l C a c h e %
4581% %
4582% %
4583% %
4584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4585%
4586% ReferencePixelCache() increments the reference count associated with the
4587% pixel cache returning a pointer to the cache.
4588%
4589% The format of the ReferencePixelCache method is:
4590%
4591% Cache ReferencePixelCache(Cache cache_info)
4592%
4593% A description of each parameter follows:
4594%
4595% o cache_info: the pixel cache.
4596%
4597*/
cristya6577ff2011-09-02 19:54:26 +00004598MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004599{
4600 CacheInfo
4601 *cache_info;
4602
4603 assert(cache != (Cache *) NULL);
4604 cache_info=(CacheInfo *) cache;
4605 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004606 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004607 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004608 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004609 return(cache_info);
4610}
4611
4612/*
4613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4614% %
4615% %
4616% %
4617+ S e t P i x e l C a c h e M e t h o d s %
4618% %
4619% %
4620% %
4621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4622%
4623% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4624%
4625% The format of the SetPixelCacheMethods() method is:
4626%
4627% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4628%
4629% A description of each parameter follows:
4630%
4631% o cache: the pixel cache.
4632%
4633% o cache_methods: Specifies a pointer to a CacheMethods structure.
4634%
4635*/
cristya6577ff2011-09-02 19:54:26 +00004636MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004637{
4638 CacheInfo
4639 *cache_info;
4640
4641 GetOneAuthenticPixelFromHandler
4642 get_one_authentic_pixel_from_handler;
4643
4644 GetOneVirtualPixelFromHandler
4645 get_one_virtual_pixel_from_handler;
4646
4647 /*
4648 Set cache pixel methods.
4649 */
4650 assert(cache != (Cache) NULL);
4651 assert(cache_methods != (CacheMethods *) NULL);
4652 cache_info=(CacheInfo *) cache;
4653 assert(cache_info->signature == MagickSignature);
4654 if (cache_info->debug != MagickFalse)
4655 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4656 cache_info->filename);
4657 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4658 cache_info->methods.get_virtual_pixel_handler=
4659 cache_methods->get_virtual_pixel_handler;
4660 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4661 cache_info->methods.destroy_pixel_handler=
4662 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004663 if (cache_methods->get_virtual_metacontent_from_handler !=
4664 (GetVirtualMetacontentFromHandler) NULL)
4665 cache_info->methods.get_virtual_metacontent_from_handler=
4666 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004667 if (cache_methods->get_authentic_pixels_handler !=
4668 (GetAuthenticPixelsHandler) NULL)
4669 cache_info->methods.get_authentic_pixels_handler=
4670 cache_methods->get_authentic_pixels_handler;
4671 if (cache_methods->queue_authentic_pixels_handler !=
4672 (QueueAuthenticPixelsHandler) NULL)
4673 cache_info->methods.queue_authentic_pixels_handler=
4674 cache_methods->queue_authentic_pixels_handler;
4675 if (cache_methods->sync_authentic_pixels_handler !=
4676 (SyncAuthenticPixelsHandler) NULL)
4677 cache_info->methods.sync_authentic_pixels_handler=
4678 cache_methods->sync_authentic_pixels_handler;
4679 if (cache_methods->get_authentic_pixels_from_handler !=
4680 (GetAuthenticPixelsFromHandler) NULL)
4681 cache_info->methods.get_authentic_pixels_from_handler=
4682 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004683 if (cache_methods->get_authentic_metacontent_from_handler !=
4684 (GetAuthenticMetacontentFromHandler) NULL)
4685 cache_info->methods.get_authentic_metacontent_from_handler=
4686 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004687 get_one_virtual_pixel_from_handler=
4688 cache_info->methods.get_one_virtual_pixel_from_handler;
4689 if (get_one_virtual_pixel_from_handler !=
4690 (GetOneVirtualPixelFromHandler) NULL)
4691 cache_info->methods.get_one_virtual_pixel_from_handler=
4692 cache_methods->get_one_virtual_pixel_from_handler;
4693 get_one_authentic_pixel_from_handler=
4694 cache_methods->get_one_authentic_pixel_from_handler;
4695 if (get_one_authentic_pixel_from_handler !=
4696 (GetOneAuthenticPixelFromHandler) NULL)
4697 cache_info->methods.get_one_authentic_pixel_from_handler=
4698 cache_methods->get_one_authentic_pixel_from_handler;
4699}
4700
4701/*
4702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703% %
4704% %
4705% %
4706+ S e t P i x e l C a c h e N e x u s P i x e l s %
4707% %
4708% %
4709% %
4710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4711%
4712% SetPixelCacheNexusPixels() defines the region of the cache for the
4713% specified cache nexus.
4714%
4715% The format of the SetPixelCacheNexusPixels() method is:
4716%
cristy4c08aed2011-07-01 19:47:50 +00004717% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004718% const RectangleInfo *region,NexusInfo *nexus_info,
4719% ExceptionInfo *exception)
4720%
4721% A description of each parameter follows:
4722%
4723% o image: the image.
4724%
4725% o region: A pointer to the RectangleInfo structure that defines the
4726% region of this particular cache nexus.
4727%
4728% o nexus_info: the cache nexus to set.
4729%
4730% o exception: return any errors or warnings in this structure.
4731%
4732*/
cristyabd6e372010-09-15 19:11:26 +00004733
4734static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4735 NexusInfo *nexus_info,ExceptionInfo *exception)
4736{
4737 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4738 return(MagickFalse);
4739 nexus_info->mapped=MagickFalse;
cristy64c3edf2012-04-13 18:50:13 +00004740 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00004741 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004742 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004743 {
4744 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004745 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004746 nexus_info->length);
4747 }
cristy4c08aed2011-07-01 19:47:50 +00004748 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004749 {
4750 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004751 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004752 cache_info->filename);
4753 return(MagickFalse);
4754 }
4755 return(MagickTrue);
4756}
4757
cristy4c08aed2011-07-01 19:47:50 +00004758static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004759 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4760{
4761 CacheInfo
4762 *cache_info;
4763
4764 MagickBooleanType
4765 status;
4766
cristy3ed852e2009-09-05 21:47:34 +00004767 MagickSizeType
4768 length,
4769 number_pixels;
4770
cristy3ed852e2009-09-05 21:47:34 +00004771 cache_info=(CacheInfo *) image->cache;
4772 assert(cache_info->signature == MagickSignature);
4773 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004774 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004775 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004776 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004777 {
cristybb503372010-05-27 20:51:26 +00004778 ssize_t
cristybad067a2010-02-15 17:20:55 +00004779 x,
4780 y;
cristy3ed852e2009-09-05 21:47:34 +00004781
cristyeaedf062010-05-29 22:36:02 +00004782 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4783 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004784 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4785 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004786 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004787 ((nexus_info->region.width == cache_info->columns) ||
4788 ((nexus_info->region.width % cache_info->columns) == 0)))))
4789 {
4790 MagickOffsetType
4791 offset;
4792
4793 /*
4794 Pixels are accessed directly from memory.
4795 */
4796 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4797 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004798 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004799 offset;
4800 nexus_info->metacontent=(void *) NULL;
4801 if (cache_info->metacontent_extent != 0)
4802 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4803 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00004804 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004805 }
4806 }
4807 /*
4808 Pixels are stored in a cache region until they are synced to the cache.
4809 */
4810 number_pixels=(MagickSizeType) nexus_info->region.width*
4811 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004812 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004813 if (cache_info->metacontent_extent != 0)
4814 length+=number_pixels*cache_info->metacontent_extent;
4815 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004816 {
4817 nexus_info->length=length;
4818 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4819 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004820 {
4821 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004822 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004823 }
cristy3ed852e2009-09-05 21:47:34 +00004824 }
4825 else
4826 if (nexus_info->length != length)
4827 {
4828 RelinquishCacheNexusPixels(nexus_info);
4829 nexus_info->length=length;
4830 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4831 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004832 {
4833 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004834 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004835 }
cristy3ed852e2009-09-05 21:47:34 +00004836 }
4837 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004838 nexus_info->metacontent=(void *) NULL;
4839 if (cache_info->metacontent_extent != 0)
4840 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004841 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004842 return(nexus_info->pixels);
4843}
4844
4845/*
4846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4847% %
4848% %
4849% %
4850% 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 %
4851% %
4852% %
4853% %
4854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4855%
4856% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4857% pixel cache and returns the previous setting. A virtual pixel is any pixel
4858% access that is outside the boundaries of the image cache.
4859%
4860% The format of the SetPixelCacheVirtualMethod() method is:
4861%
cristy387430f2012-02-07 13:09:46 +00004862% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4863% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004864%
4865% A description of each parameter follows:
4866%
4867% o image: the image.
4868%
4869% o virtual_pixel_method: choose the type of virtual pixel.
4870%
cristy387430f2012-02-07 13:09:46 +00004871% o exception: return any errors or warnings in this structure.
4872%
cristy3ed852e2009-09-05 21:47:34 +00004873*/
cristy3d4cb882012-02-07 19:11:26 +00004874
4875static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4876 ExceptionInfo *exception)
4877{
cristy23d198a2012-03-13 13:48:08 +00004878 CacheView
4879 *image_view;
4880
cristy3d4cb882012-02-07 19:11:26 +00004881 CacheInfo
4882 *cache_info;
4883
4884 MagickBooleanType
4885 status;
4886
4887 ssize_t
4888 y;
4889
4890 assert(image != (Image *) NULL);
4891 assert(image->signature == MagickSignature);
4892 if (image->debug != MagickFalse)
4893 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4894 assert(image->cache != (Cache) NULL);
4895 cache_info=(CacheInfo *) image->cache;
4896 assert(cache_info->signature == MagickSignature);
4897 image->matte=MagickTrue;
4898 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004899 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004900#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00004901 #pragma omp parallel for schedule(static) shared(status) \
4902 if ((image->rows*image->columns) > 8192) \
4903 num_threads(GetMagickResourceLimit(ThreadResource))
cristy3d4cb882012-02-07 19:11:26 +00004904#endif
4905 for (y=0; y < (ssize_t) image->rows; y++)
4906 {
cristy3d4cb882012-02-07 19:11:26 +00004907 register Quantum
4908 *restrict q;
4909
4910 register ssize_t
4911 x;
4912
4913 if (status == MagickFalse)
4914 continue;
cristy23d198a2012-03-13 13:48:08 +00004915 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004916 if (q == (Quantum *) NULL)
4917 {
4918 status=MagickFalse;
4919 continue;
4920 }
4921 for (x=0; x < (ssize_t) image->columns; x++)
4922 {
4923 SetPixelAlpha(image,alpha,q);
4924 q+=GetPixelChannels(image);
4925 }
cristy23d198a2012-03-13 13:48:08 +00004926 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004927 }
cristy23d198a2012-03-13 13:48:08 +00004928 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004929 return(status);
4930}
4931
cristy387430f2012-02-07 13:09:46 +00004932MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4933 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004934{
4935 CacheInfo
4936 *cache_info;
4937
4938 VirtualPixelMethod
4939 method;
4940
4941 assert(image != (Image *) NULL);
4942 assert(image->signature == MagickSignature);
4943 if (image->debug != MagickFalse)
4944 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4945 assert(image->cache != (Cache) NULL);
4946 cache_info=(CacheInfo *) image->cache;
4947 assert(cache_info->signature == MagickSignature);
4948 method=cache_info->virtual_pixel_method;
4949 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004950 switch (virtual_pixel_method)
4951 {
4952 case BackgroundVirtualPixelMethod:
4953 {
4954 if ((image->background_color.matte != MagickFalse) &&
4955 (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 case TransparentVirtualPixelMethod:
4960 {
4961 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00004962 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004963 break;
4964 }
4965 default:
4966 break;
4967 }
cristy3ed852e2009-09-05 21:47:34 +00004968 return(method);
4969}
4970
4971/*
4972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4973% %
4974% %
4975% %
4976+ 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 %
4977% %
4978% %
4979% %
4980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4981%
4982% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4983% in-memory or disk cache. The method returns MagickTrue if the pixel region
4984% is synced, otherwise MagickFalse.
4985%
4986% The format of the SyncAuthenticPixelCacheNexus() method is:
4987%
4988% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4989% NexusInfo *nexus_info,ExceptionInfo *exception)
4990%
4991% A description of each parameter follows:
4992%
4993% o image: the image.
4994%
4995% o nexus_info: the cache nexus to sync.
4996%
4997% o exception: return any errors or warnings in this structure.
4998%
4999*/
cristya6577ff2011-09-02 19:54:26 +00005000MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005001 NexusInfo *nexus_info,ExceptionInfo *exception)
5002{
5003 CacheInfo
5004 *cache_info;
5005
5006 MagickBooleanType
5007 status;
5008
5009 /*
5010 Transfer pixels to the cache.
5011 */
5012 assert(image != (Image *) NULL);
5013 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005014 if (image->cache == (Cache) NULL)
5015 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5016 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005017 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005018 if (cache_info->type == UndefinedCache)
5019 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005020 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005021 return(MagickTrue);
5022 assert(cache_info->signature == MagickSignature);
5023 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005024 if ((cache_info->metacontent_extent != 0) &&
5025 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005026 return(MagickFalse);
5027 return(status);
5028}
5029
5030/*
5031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5032% %
5033% %
5034% %
5035+ S y n c A u t h e n t i c P i x e l C a c h e %
5036% %
5037% %
5038% %
5039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5040%
5041% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5042% or disk cache. The method returns MagickTrue if the pixel region is synced,
5043% otherwise MagickFalse.
5044%
5045% The format of the SyncAuthenticPixelsCache() method is:
5046%
5047% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5048% ExceptionInfo *exception)
5049%
5050% A description of each parameter follows:
5051%
5052% o image: the image.
5053%
5054% o exception: return any errors or warnings in this structure.
5055%
5056*/
5057static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5058 ExceptionInfo *exception)
5059{
5060 CacheInfo
5061 *cache_info;
5062
cristy5c9e6f22010-09-17 17:31:01 +00005063 const int
5064 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005065
cristy4c08aed2011-07-01 19:47:50 +00005066 MagickBooleanType
5067 status;
5068
cristye7cc7cf2010-09-21 13:26:47 +00005069 assert(image != (Image *) NULL);
5070 assert(image->signature == MagickSignature);
5071 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005072 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005073 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005074 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005075 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5076 exception);
5077 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005078}
5079
5080/*
5081%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5082% %
5083% %
5084% %
5085% S y n c A u t h e n t i c P i x e l s %
5086% %
5087% %
5088% %
5089%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5090%
5091% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5092% The method returns MagickTrue if the pixel region is flushed, otherwise
5093% MagickFalse.
5094%
5095% The format of the SyncAuthenticPixels() method is:
5096%
5097% MagickBooleanType SyncAuthenticPixels(Image *image,
5098% ExceptionInfo *exception)
5099%
5100% A description of each parameter follows:
5101%
5102% o image: the image.
5103%
5104% o exception: return any errors or warnings in this structure.
5105%
5106*/
5107MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5108 ExceptionInfo *exception)
5109{
5110 CacheInfo
5111 *cache_info;
5112
cristy2036f5c2010-09-19 21:18:17 +00005113 const int
5114 id = GetOpenMPThreadId();
5115
cristy4c08aed2011-07-01 19:47:50 +00005116 MagickBooleanType
5117 status;
5118
cristy3ed852e2009-09-05 21:47:34 +00005119 assert(image != (Image *) NULL);
5120 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005121 assert(image->cache != (Cache) NULL);
5122 cache_info=(CacheInfo *) image->cache;
5123 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005124 if (cache_info->methods.sync_authentic_pixels_handler !=
5125 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005126 {
5127 status=cache_info->methods.sync_authentic_pixels_handler(image,
5128 exception);
5129 return(status);
5130 }
cristy2036f5c2010-09-19 21:18:17 +00005131 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005132 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5133 exception);
5134 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005135}
5136
5137/*
5138%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5139% %
5140% %
5141% %
cristyd1dd6e42011-09-04 01:46:08 +00005142+ 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 +00005143% %
5144% %
5145% %
5146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5147%
5148% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5149% The method returns MagickTrue if the pixel region is flushed, otherwise
5150% MagickFalse.
5151%
5152% The format of the SyncImagePixelCache() method is:
5153%
5154% MagickBooleanType SyncImagePixelCache(Image *image,
5155% ExceptionInfo *exception)
5156%
5157% A description of each parameter follows:
5158%
5159% o image: the image.
5160%
5161% o exception: return any errors or warnings in this structure.
5162%
5163*/
cristyd1dd6e42011-09-04 01:46:08 +00005164MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005165 ExceptionInfo *exception)
5166{
5167 CacheInfo
5168 *cache_info;
5169
5170 assert(image != (Image *) NULL);
5171 assert(exception != (ExceptionInfo *) NULL);
5172 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5173 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5174}
5175
5176/*
5177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5178% %
5179% %
5180% %
cristy4c08aed2011-07-01 19:47:50 +00005181+ 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 +00005182% %
5183% %
5184% %
5185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5186%
cristy4c08aed2011-07-01 19:47:50 +00005187% WritePixelCacheMetacontent() writes the meta-content to the specified region
5188% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005189%
cristy4c08aed2011-07-01 19:47:50 +00005190% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005191%
cristy4c08aed2011-07-01 19:47:50 +00005192% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005193% NexusInfo *nexus_info,ExceptionInfo *exception)
5194%
5195% A description of each parameter follows:
5196%
5197% o cache_info: the pixel cache.
5198%
cristy4c08aed2011-07-01 19:47:50 +00005199% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005200%
5201% o exception: return any errors or warnings in this structure.
5202%
5203*/
cristy4c08aed2011-07-01 19:47:50 +00005204static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005205 NexusInfo *nexus_info,ExceptionInfo *exception)
5206{
5207 MagickOffsetType
5208 count,
5209 offset;
5210
5211 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005212 extent,
5213 length;
cristy3ed852e2009-09-05 21:47:34 +00005214
cristy4c08aed2011-07-01 19:47:50 +00005215 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005216 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005217
cristybb503372010-05-27 20:51:26 +00005218 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005219 y;
5220
cristybb503372010-05-27 20:51:26 +00005221 size_t
cristy3ed852e2009-09-05 21:47:34 +00005222 rows;
5223
cristy4c08aed2011-07-01 19:47:50 +00005224 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005225 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005226 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005227 return(MagickTrue);
5228 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5229 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005230 length=(MagickSizeType) nexus_info->region.width*
5231 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005232 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005233 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005234 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005235 switch (cache_info->type)
5236 {
5237 case MemoryCache:
5238 case MapCache:
5239 {
cristy4c08aed2011-07-01 19:47:50 +00005240 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005241 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005242
5243 /*
cristy4c08aed2011-07-01 19:47:50 +00005244 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005245 */
cristydd341db2010-03-04 19:06:38 +00005246 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005247 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005248 {
cristy48078b12010-09-23 17:11:01 +00005249 length=extent;
cristydd341db2010-03-04 19:06:38 +00005250 rows=1UL;
5251 }
cristy4c08aed2011-07-01 19:47:50 +00005252 q=(unsigned char *) cache_info->metacontent+offset*
5253 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005254 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005255 {
cristy8f036fe2010-09-18 02:02:00 +00005256 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005257 p+=nexus_info->region.width*cache_info->metacontent_extent;
5258 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005259 }
5260 break;
5261 }
5262 case DiskCache:
5263 {
5264 /*
cristy4c08aed2011-07-01 19:47:50 +00005265 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005266 */
5267 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5268 {
5269 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5270 cache_info->cache_filename);
5271 return(MagickFalse);
5272 }
cristydd341db2010-03-04 19:06:38 +00005273 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005274 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005275 {
cristy48078b12010-09-23 17:11:01 +00005276 length=extent;
cristydd341db2010-03-04 19:06:38 +00005277 rows=1UL;
5278 }
cristy48078b12010-09-23 17:11:01 +00005279 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005280 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005281 {
cristy48078b12010-09-23 17:11:01 +00005282 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005283 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005284 cache_info->metacontent_extent,length,(const unsigned char *) p);
5285 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005286 break;
cristy4c08aed2011-07-01 19:47:50 +00005287 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005288 offset+=cache_info->columns;
5289 }
cristyc11dace2012-01-24 16:39:46 +00005290 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5291 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005292 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005293 {
5294 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5295 cache_info->cache_filename);
5296 return(MagickFalse);
5297 }
5298 break;
5299 }
5300 default:
5301 break;
5302 }
5303 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005304 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005305 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005306 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005307 nexus_info->region.width,(double) nexus_info->region.height,(double)
5308 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005309 return(MagickTrue);
5310}
5311
5312/*
5313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5314% %
5315% %
5316% %
5317+ W r i t e C a c h e P i x e l s %
5318% %
5319% %
5320% %
5321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5322%
5323% WritePixelCachePixels() writes image pixels to the specified region of the
5324% pixel cache.
5325%
5326% The format of the WritePixelCachePixels() method is:
5327%
5328% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5329% NexusInfo *nexus_info,ExceptionInfo *exception)
5330%
5331% A description of each parameter follows:
5332%
5333% o cache_info: the pixel cache.
5334%
5335% o nexus_info: the cache nexus to write the pixels.
5336%
5337% o exception: return any errors or warnings in this structure.
5338%
5339*/
5340static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5341 NexusInfo *nexus_info,ExceptionInfo *exception)
5342{
5343 MagickOffsetType
5344 count,
5345 offset;
5346
5347 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005348 extent,
5349 length;
cristy3ed852e2009-09-05 21:47:34 +00005350
cristy4c08aed2011-07-01 19:47:50 +00005351 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005352 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005353
cristybb503372010-05-27 20:51:26 +00005354 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005355 y;
5356
cristybb503372010-05-27 20:51:26 +00005357 size_t
cristy3ed852e2009-09-05 21:47:34 +00005358 rows;
5359
cristy4c08aed2011-07-01 19:47:50 +00005360 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005361 return(MagickTrue);
5362 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5363 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005364 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005365 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005366 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005367 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005368 p=nexus_info->pixels;
5369 switch (cache_info->type)
5370 {
5371 case MemoryCache:
5372 case MapCache:
5373 {
cristy4c08aed2011-07-01 19:47:50 +00005374 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005375 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005376
5377 /*
5378 Write pixels to memory.
5379 */
cristydd341db2010-03-04 19:06:38 +00005380 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005381 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005382 {
cristy48078b12010-09-23 17:11:01 +00005383 length=extent;
cristydd341db2010-03-04 19:06:38 +00005384 rows=1UL;
5385 }
cristyed231572011-07-14 02:18:59 +00005386 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005387 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005388 {
cristy8f036fe2010-09-18 02:02:00 +00005389 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005390 p+=nexus_info->region.width*cache_info->number_channels;
5391 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005392 }
5393 break;
5394 }
5395 case DiskCache:
5396 {
5397 /*
5398 Write pixels to disk.
5399 */
5400 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5401 {
5402 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5403 cache_info->cache_filename);
5404 return(MagickFalse);
5405 }
cristydd341db2010-03-04 19:06:38 +00005406 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005407 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005408 {
cristy48078b12010-09-23 17:11:01 +00005409 length=extent;
cristydd341db2010-03-04 19:06:38 +00005410 rows=1UL;
5411 }
cristybb503372010-05-27 20:51:26 +00005412 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005413 {
5414 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005415 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005416 p);
5417 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005418 break;
cristyed231572011-07-14 02:18:59 +00005419 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005420 offset+=cache_info->columns;
5421 }
cristyc11dace2012-01-24 16:39:46 +00005422 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5423 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005424 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005425 {
5426 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5427 cache_info->cache_filename);
5428 return(MagickFalse);
5429 }
5430 break;
5431 }
5432 default:
5433 break;
5434 }
5435 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005436 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005437 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005438 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005439 nexus_info->region.width,(double) nexus_info->region.height,(double)
5440 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005441 return(MagickTrue);
5442}