blob: 669f12c6e0cb0220633db85b2404a19d931fbb1d [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"
cristyadf82722012-05-11 17:34:16 +000057#include "MagickCore/memory-private.h"
cristyd2d11ec2012-03-28 13:53:49 +000058#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000059#include "MagickCore/pixel.h"
60#include "MagickCore/pixel-accessor.h"
61#include "MagickCore/policy.h"
62#include "MagickCore/quantum.h"
63#include "MagickCore/random_.h"
64#include "MagickCore/resource_.h"
65#include "MagickCore/semaphore.h"
66#include "MagickCore/splay-tree.h"
67#include "MagickCore/string_.h"
68#include "MagickCore/string-private.h"
69#include "MagickCore/thread-private.h"
70#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000071#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000072#if defined(MAGICKCORE_ZLIB_DELEGATE)
73#include "zlib.h"
74#endif
75
76/*
cristy30097232010-07-01 02:16:30 +000077 Define declarations.
78*/
79#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
cristyc11dace2012-01-24 16:39:46 +000080#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
81 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
cristy30097232010-07-01 02:16:30 +000082
83/*
cristy3ed852e2009-09-05 21:47:34 +000084 Typedef declarations.
85*/
86typedef struct _MagickModulo
87{
cristybb503372010-05-27 20:51:26 +000088 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000089 quotient,
90 remainder;
91} MagickModulo;
92
93struct _NexusInfo
94{
95 MagickBooleanType
96 mapped;
97
98 RectangleInfo
99 region;
100
101 MagickSizeType
102 length;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000105 *cache,
106 *pixels;
107
cristy4c08aed2011-07-01 19:47:50 +0000108 void
109 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000110
cristybb503372010-05-27 20:51:26 +0000111 size_t
cristy3ed852e2009-09-05 21:47:34 +0000112 signature;
113};
114
115/*
116 Forward declarations.
117*/
118#if defined(__cplusplus) || defined(c_plusplus)
119extern "C" {
120#endif
121
cristy19596d62012-02-19 00:24:59 +0000122static Cache
123 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
124 magick_hot_spot;
125
cristy4c08aed2011-07-01 19:47:50 +0000126static const Quantum
cristybb503372010-05-27 20:51:26 +0000127 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000128 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000129 *GetVirtualPixelsCache(const Image *);
130
cristy4c08aed2011-07-01 19:47:50 +0000131static const void
132 *GetVirtualMetacontentFromCache(const Image *);
133
cristy3ed852e2009-09-05 21:47:34 +0000134static MagickBooleanType
cristy74ce05d2012-05-06 18:41:18 +0000135 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
136 ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000137 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000138 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000139 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000140 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000141 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
142 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000143 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000144 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
145
cristy4c08aed2011-07-01 19:47:50 +0000146static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000147 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
148 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000149 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
150 const size_t,ExceptionInfo *),
cristy265a2b22012-05-11 12:48:50 +0000151 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
152 NexusInfo *,ExceptionInfo *) magick_hot_spot;
cristy3ed852e2009-09-05 21:47:34 +0000153
154#if defined(__cplusplus) || defined(c_plusplus)
155}
156#endif
157
158/*
159 Global declarations.
160*/
161static volatile MagickBooleanType
162 instantiate_cache = MagickFalse;
163
164static SemaphoreInfo
165 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000166
167/*
168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169% %
170% %
171% %
172+ A c q u i r e P i x e l C a c h e %
173% %
174% %
175% %
176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177%
178% AcquirePixelCache() acquires a pixel cache.
179%
180% The format of the AcquirePixelCache() method is:
181%
cristybb503372010-05-27 20:51:26 +0000182% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000183%
184% A description of each parameter follows:
185%
186% o number_threads: the number of nexus threads.
187%
188*/
cristya6577ff2011-09-02 19:54:26 +0000189MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000190{
191 CacheInfo
192 *cache_info;
193
cristya64b85d2011-09-14 01:02:31 +0000194 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000195 if (cache_info == (CacheInfo *) NULL)
196 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
197 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
198 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000199 cache_info->mode=IOMode;
cristyc511e882012-04-16 21:11:14 +0000200 cache_info->colorspace=sRGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +0000201 cache_info->file=(-1);
202 cache_info->id=GetMagickThreadId();
203 cache_info->number_threads=number_threads;
204 if (number_threads == 0)
cristyfeeb98d2012-05-09 16:32:12 +0000205 cache_info->number_threads=GetOpenMPMaximumThreads();
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
207 if (cache_info->nexus_info == (NexusInfo **) NULL)
208 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000209 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000210 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000211 cache_info->disk_semaphore=AllocateSemaphoreInfo();
212 cache_info->debug=IsEventLogging();
213 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000214 return((Cache ) cache_info);
215}
216
217/*
218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219% %
220% %
221% %
222% A c q u i r e P i x e l C a c h e N e x u s %
223% %
224% %
225% %
226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227%
228% AcquirePixelCacheNexus() allocates the NexusInfo structure.
229%
230% The format of the AcquirePixelCacheNexus method is:
231%
cristybb503372010-05-27 20:51:26 +0000232% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000233%
234% A description of each parameter follows:
235%
236% o number_threads: the number of nexus threads.
237%
238*/
cristya6577ff2011-09-02 19:54:26 +0000239MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000240{
cristy3ed852e2009-09-05 21:47:34 +0000241 NexusInfo
242 **nexus_info;
243
cristye076a6e2010-08-15 19:59:43 +0000244 register ssize_t
245 i;
246
cristy64c3edf2012-04-13 18:50:13 +0000247 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000248 sizeof(*nexus_info));
249 if (nexus_info == (NexusInfo **) NULL)
250 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000251 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
252 sizeof(**nexus_info));
253 if (nexus_info[0] == (NexusInfo *) NULL)
254 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
255 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000256 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000257 {
cristye5f87c82012-02-14 12:44:17 +0000258 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000259 nexus_info[i]->signature=MagickSignature;
260 }
261 return(nexus_info);
262}
263
264/*
265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266% %
267% %
268% %
cristyd43a46b2010-01-21 02:13:41 +0000269+ A c q u i r e P i x e l C a c h e P i x e l s %
270% %
271% %
272% %
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274%
275% AcquirePixelCachePixels() returns the pixels associated with the specified
276% image.
277%
278% The format of the AcquirePixelCachePixels() method is:
279%
280% const void *AcquirePixelCachePixels(const Image *image,
281% MagickSizeType *length,ExceptionInfo *exception)
282%
283% A description of each parameter follows:
284%
285% o image: the image.
286%
287% o length: the pixel cache length.
288%
289% o exception: return any errors or warnings in this structure.
290%
291*/
cristyd1dd6e42011-09-04 01:46:08 +0000292MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000293 MagickSizeType *length,ExceptionInfo *exception)
294{
295 CacheInfo
296 *cache_info;
297
298 assert(image != (const Image *) NULL);
299 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000300 assert(exception != (ExceptionInfo *) NULL);
301 assert(exception->signature == MagickSignature);
302 assert(image->cache != (Cache) NULL);
303 cache_info=(CacheInfo *) image->cache;
304 assert(cache_info->signature == MagickSignature);
305 *length=0;
306 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
307 return((const void *) NULL);
308 *length=cache_info->length;
309 return((const void *) cache_info->pixels);
310}
311
312/*
313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314% %
315% %
316% %
cristyf34a1452009-10-24 22:29:27 +0000317+ C a c h e C o m p o n e n t G e n e s i s %
318% %
319% %
320% %
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322%
323% CacheComponentGenesis() instantiates the cache component.
324%
325% The format of the CacheComponentGenesis method is:
326%
327% MagickBooleanType CacheComponentGenesis(void)
328%
329*/
cristy5ff4eaf2011-09-03 01:38:02 +0000330MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000331{
cristy165b6092009-10-26 13:52:10 +0000332 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000333 return(MagickTrue);
334}
335
336/*
337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338% %
339% %
340% %
341+ C a c h e C o m p o n e n t T e r m i n u s %
342% %
343% %
344% %
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346%
347% CacheComponentTerminus() destroys the cache component.
348%
349% The format of the CacheComponentTerminus() method is:
350%
351% CacheComponentTerminus(void)
352%
353*/
cristy5ff4eaf2011-09-03 01:38:02 +0000354MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000355{
cristy18b17442009-10-25 18:36:48 +0000356 if (cache_semaphore == (SemaphoreInfo *) NULL)
357 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000358 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000359 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000360 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000361 DestroySemaphoreInfo(&cache_semaphore);
362}
363
364/*
365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366% %
367% %
368% %
cristy3ed852e2009-09-05 21:47:34 +0000369+ C l o n e P i x e l C a c h e %
370% %
371% %
372% %
373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374%
375% ClonePixelCache() clones a pixel cache.
376%
377% The format of the ClonePixelCache() method is:
378%
379% Cache ClonePixelCache(const Cache cache)
380%
381% A description of each parameter follows:
382%
383% o cache: the pixel cache.
384%
385*/
cristya6577ff2011-09-02 19:54:26 +0000386MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000387{
388 CacheInfo
389 *clone_info;
390
391 const CacheInfo
392 *cache_info;
393
cristy9f027d12011-09-21 01:17:17 +0000394 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000395 cache_info=(const CacheInfo *) cache;
396 assert(cache_info->signature == MagickSignature);
397 if (cache_info->debug != MagickFalse)
398 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
399 cache_info->filename);
400 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
401 if (clone_info == (Cache) NULL)
402 return((Cache) NULL);
403 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
404 return((Cache ) clone_info);
405}
406
407/*
408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
409% %
410% %
411% %
cristy60c44a82009-10-07 00:58:49 +0000412+ 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 +0000413% %
414% %
415% %
416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
417% ClonePixelCachePixels() clones the source pixel cache to the destination
418% cache.
419%
420% The format of the ClonePixelCachePixels() method is:
421%
422% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
423% CacheInfo *source_info,ExceptionInfo *exception)
424%
425% A description of each parameter follows:
426%
427% o cache_info: the pixel cache.
428%
429% o source_info: the source pixel cache.
430%
431% o exception: return any errors or warnings in this structure.
432%
433*/
434
435static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
436{
437 int
438 status;
439
cristy5ee247a2010-02-12 15:42:34 +0000440 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000441 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000442 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000443 {
444 status=close(cache_info->file);
445 cache_info->file=(-1);
446 RelinquishMagickResource(FileResource,1);
447 }
cristyf84a1932010-01-03 18:00:18 +0000448 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000449 return(status == -1 ? MagickFalse : MagickTrue);
450}
451
cristy3ed852e2009-09-05 21:47:34 +0000452static inline MagickSizeType MagickMax(const MagickSizeType x,
453 const MagickSizeType y)
454{
455 if (x > y)
456 return(x);
457 return(y);
458}
459
460static inline MagickSizeType MagickMin(const MagickSizeType x,
461 const MagickSizeType y)
462{
463 if (x < y)
464 return(x);
465 return(y);
466}
467
468static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
469 const MapMode mode)
470{
471 int
472 file;
473
474 /*
475 Open pixel cache on disk.
476 */
cristyf84a1932010-01-03 18:00:18 +0000477 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000478 if (cache_info->file != -1)
479 {
cristyf84a1932010-01-03 18:00:18 +0000480 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000481 return(MagickTrue); /* cache already open */
482 }
cristy3ed852e2009-09-05 21:47:34 +0000483 if (*cache_info->cache_filename == '\0')
484 file=AcquireUniqueFileResource(cache_info->cache_filename);
485 else
486 switch (mode)
487 {
488 case ReadMode:
489 {
cristy18c6c272011-09-23 14:40:37 +0000490 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000491 break;
492 }
493 case WriteMode:
494 {
cristy18c6c272011-09-23 14:40:37 +0000495 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
496 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000497 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000498 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000499 break;
500 }
501 case IOMode:
502 default:
503 {
cristy18c6c272011-09-23 14:40:37 +0000504 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000505 O_EXCL,S_MODE);
506 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000507 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000508 break;
509 }
510 }
511 if (file == -1)
512 {
cristyf84a1932010-01-03 18:00:18 +0000513 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000514 return(MagickFalse);
515 }
516 (void) AcquireMagickResource(FileResource,1);
517 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000518 cache_info->mode=mode;
cristyf84a1932010-01-03 18:00:18 +0000519 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000520 return(MagickTrue);
521}
522
cristyf1832792012-05-08 18:38:18 +0000523static inline MagickOffsetType ReadPixelCacheRegion(
524 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
525 const MagickSizeType length,unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000526{
527 register MagickOffsetType
528 i;
529
530 ssize_t
531 count;
532
533#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000534 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000535 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000536 {
cristyf84a1932010-01-03 18:00:18 +0000537 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000538 return((MagickOffsetType) -1);
539 }
540#endif
541 count=0;
542 for (i=0; i < (MagickOffsetType) length; i+=count)
543 {
544#if !defined(MAGICKCORE_HAVE_PREAD)
545 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
546 (MagickSizeType) SSIZE_MAX));
547#else
548 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000549 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000550#endif
551 if (count > 0)
552 continue;
553 count=0;
554 if (errno != EINTR)
555 {
556 i=(-1);
557 break;
558 }
559 }
560#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000561 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000562#endif
563 return(i);
564}
565
cristyf1832792012-05-08 18:38:18 +0000566static inline MagickOffsetType WritePixelCacheRegion(
567 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
568 const MagickSizeType length,const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000569{
570 register MagickOffsetType
571 i;
572
573 ssize_t
574 count;
575
576#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000578 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return((MagickOffsetType) -1);
582 }
583#endif
584 count=0;
585 for (i=0; i < (MagickOffsetType) length; i+=count)
586 {
587#if !defined(MAGICKCORE_HAVE_PWRITE)
588 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
589 (MagickSizeType) SSIZE_MAX));
590#else
591 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000592 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000593#endif
594 if (count > 0)
595 continue;
596 count=0;
597 if (errno != EINTR)
598 {
599 i=(-1);
600 break;
601 }
602 }
603#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000604 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000605#endif
606 return(i);
607}
608
cristy4c08aed2011-07-01 19:47:50 +0000609static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000610 CacheInfo *cache_info,ExceptionInfo *exception)
611{
612 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000613 count;
cristy3ed852e2009-09-05 21:47:34 +0000614
cristy4c08aed2011-07-01 19:47:50 +0000615 register MagickOffsetType
616 i;
cristye076a6e2010-08-15 19:59:43 +0000617
cristybb503372010-05-27 20:51:26 +0000618 size_t
cristy4c08aed2011-07-01 19:47:50 +0000619 length;
cristy3ed852e2009-09-05 21:47:34 +0000620
cristy4c08aed2011-07-01 19:47:50 +0000621 unsigned char
622 *blob;
623
624 /*
625 Clone pixel cache (both caches on disk).
626 */
cristy3ed852e2009-09-05 21:47:34 +0000627 if (cache_info->debug != MagickFalse)
628 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000629 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000630 sizeof(*blob));
631 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000632 {
cristy4c08aed2011-07-01 19:47:50 +0000633 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000634 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000635 cache_info->filename);
636 return(MagickFalse);
637 }
cristy3dedf062011-07-02 14:07:40 +0000638 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000639 {
640 blob=(unsigned char *) RelinquishMagickMemory(blob);
641 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
642 cache_info->cache_filename);
643 return(MagickFalse);
644 }
cristy3dedf062011-07-02 14:07:40 +0000645 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000646 {
647 (void) ClosePixelCacheOnDisk(cache_info);
648 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000649 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
650 clone_info->cache_filename);
651 return(MagickFalse);
652 }
cristy4c08aed2011-07-01 19:47:50 +0000653 count=0;
654 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000655 {
cristy4c08aed2011-07-01 19:47:50 +0000656 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
657 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
658 blob);
659 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000660 {
cristy4c08aed2011-07-01 19:47:50 +0000661 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
662 cache_info->cache_filename);
663 break;
cristy3ed852e2009-09-05 21:47:34 +0000664 }
cristy4c08aed2011-07-01 19:47:50 +0000665 length=(size_t) count;
666 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
667 if ((MagickSizeType) count != length)
668 {
669 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
670 clone_info->cache_filename);
671 break;
672 }
673 }
674 (void) ClosePixelCacheOnDisk(clone_info);
675 (void) ClosePixelCacheOnDisk(cache_info);
676 blob=(unsigned char *) RelinquishMagickMemory(blob);
677 if (i < (MagickOffsetType) cache_info->length)
678 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000679 return(MagickTrue);
680}
681
cristyfd24a062012-01-02 14:46:34 +0000682static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000683 CacheInfo *cache_info,ExceptionInfo *exception)
684{
685 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000686 count;
cristy3ed852e2009-09-05 21:47:34 +0000687
cristy4c08aed2011-07-01 19:47:50 +0000688 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000689 {
cristy3ed852e2009-09-05 21:47:34 +0000690 /*
cristy4c08aed2011-07-01 19:47:50 +0000691 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000692 */
cristy4c08aed2011-07-01 19:47:50 +0000693 if (cache_info->debug != MagickFalse)
694 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
695 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
696 cache_info->length);
697 return(MagickTrue);
698 }
699 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
700 {
701 /*
702 Clone pixel cache (one cache on disk, one in memory).
703 */
704 if (cache_info->debug != MagickFalse)
705 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
706 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000707 {
cristy4c08aed2011-07-01 19:47:50 +0000708 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000709 cache_info->cache_filename);
710 return(MagickFalse);
711 }
cristy4c08aed2011-07-01 19:47:50 +0000712 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
713 cache_info->length,(unsigned char *) clone_info->pixels);
714 (void) ClosePixelCacheOnDisk(cache_info);
715 if ((MagickSizeType) count != cache_info->length)
716 {
717 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
718 cache_info->cache_filename);
719 return(MagickFalse);
720 }
721 return(MagickTrue);
722 }
723 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
724 {
725 /*
726 Clone pixel cache (one cache on disk, one in memory).
727 */
728 if (clone_info->debug != MagickFalse)
729 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
730 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
731 {
732 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
733 clone_info->cache_filename);
734 return(MagickFalse);
735 }
736 count=WritePixelCacheRegion(clone_info,clone_info->offset,
737 clone_info->length,(unsigned char *) cache_info->pixels);
738 (void) ClosePixelCacheOnDisk(clone_info);
739 if ((MagickSizeType) count != clone_info->length)
740 {
741 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
742 clone_info->cache_filename);
743 return(MagickFalse);
744 }
745 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000746 }
747 /*
cristy4c08aed2011-07-01 19:47:50 +0000748 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000749 */
cristy4c08aed2011-07-01 19:47:50 +0000750 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000751}
752
cristyfd24a062012-01-02 14:46:34 +0000753static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000754 CacheInfo *cache_info,ExceptionInfo *exception)
755{
cristy4c08aed2011-07-01 19:47:50 +0000756 MagickBooleanType
757 status;
cristy3ed852e2009-09-05 21:47:34 +0000758
cristy4c08aed2011-07-01 19:47:50 +0000759 MagickOffsetType
760 cache_offset,
761 clone_offset,
762 count;
763
764 register ssize_t
765 x;
766
cristyfd24a062012-01-02 14:46:34 +0000767 register unsigned char
768 *p;
769
cristy4c08aed2011-07-01 19:47:50 +0000770 size_t
cristy3ed852e2009-09-05 21:47:34 +0000771 length;
772
cristy4c08aed2011-07-01 19:47:50 +0000773 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000774 y;
775
cristy4c08aed2011-07-01 19:47:50 +0000776 unsigned char
777 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000778
cristy4c08aed2011-07-01 19:47:50 +0000779 /*
780 Clone pixel cache (unoptimized).
781 */
cristy3ed852e2009-09-05 21:47:34 +0000782 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000783 {
cristy4c08aed2011-07-01 19:47:50 +0000784 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
786 else
787 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
789 else
790 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
792 else
793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
794 }
cristyed231572011-07-14 02:18:59 +0000795 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
796 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000797 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000798 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000799 if (blob == (unsigned char *) NULL)
800 {
801 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000802 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000803 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000804 return(MagickFalse);
805 }
cristy4c08aed2011-07-01 19:47:50 +0000806 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
807 cache_offset=0;
808 clone_offset=0;
809 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000810 {
cristy4c08aed2011-07-01 19:47:50 +0000811 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 blob=(unsigned char *) RelinquishMagickMemory(blob);
814 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000815 cache_info->cache_filename);
816 return(MagickFalse);
817 }
cristy4c08aed2011-07-01 19:47:50 +0000818 cache_offset=cache_info->offset;
819 }
820 if (clone_info->type == DiskCache)
821 {
cristy3dedf062011-07-02 14:07:40 +0000822 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000823 {
cristy4c08aed2011-07-01 19:47:50 +0000824 blob=(unsigned char *) RelinquishMagickMemory(blob);
825 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
826 clone_info->cache_filename);
827 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000828 }
cristy4c08aed2011-07-01 19:47:50 +0000829 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000830 }
831 /*
cristy4c08aed2011-07-01 19:47:50 +0000832 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000833 */
cristy4c08aed2011-07-01 19:47:50 +0000834 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000835 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000836 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000837 {
cristy4c08aed2011-07-01 19:47:50 +0000838 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000839 {
cristy9e0719b2011-12-29 03:45:45 +0000840 register ssize_t
841 i;
842
cristy3ed852e2009-09-05 21:47:34 +0000843 /*
cristy4c08aed2011-07-01 19:47:50 +0000844 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000845 */
cristyed231572011-07-14 02:18:59 +0000846 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000847 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000848 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000849 else
850 {
cristyfd24a062012-01-02 14:46:34 +0000851 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000852 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000853 {
cristy4c08aed2011-07-01 19:47:50 +0000854 status=MagickFalse;
855 break;
cristy3ed852e2009-09-05 21:47:34 +0000856 }
857 }
cristy4c08aed2011-07-01 19:47:50 +0000858 cache_offset+=length;
859 if ((y < (ssize_t) clone_info->rows) &&
860 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000861 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000862 {
cristy9e0719b2011-12-29 03:45:45 +0000863 PixelChannel
864 channel;
865
866 PixelTrait
867 traits;
868
869 ssize_t
870 offset;
871
cristy4c08aed2011-07-01 19:47:50 +0000872 /*
cristy3b8fe922011-12-29 18:56:23 +0000873 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000874 */
cristy9e0719b2011-12-29 03:45:45 +0000875 channel=clone_info->channel_map[i].channel;
876 traits=cache_info->channel_map[channel].traits;
877 if (traits == UndefinedPixelTrait)
878 {
cristy0f4425e2011-12-31 20:33:02 +0000879 clone_offset+=sizeof(Quantum);
880 continue;
cristy9e0719b2011-12-29 03:45:45 +0000881 }
cristy0f4425e2011-12-31 20:33:02 +0000882 offset=cache_info->channel_map[channel].offset;
883 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000884 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
885 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000886 else
887 {
cristy0f4425e2011-12-31 20:33:02 +0000888 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000889 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000890 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000891 {
cristy0f4425e2011-12-31 20:33:02 +0000892 status=MagickFalse;
893 break;
cristy4c08aed2011-07-01 19:47:50 +0000894 }
895 }
cristy9e0719b2011-12-29 03:45:45 +0000896 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000897 }
898 }
cristyac245f82012-05-05 17:13:57 +0000899 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000900 {
901 /*
902 Set remaining columns as undefined.
903 */
cristy888e6132012-04-23 19:54:54 +0000904 length=clone_info->number_channels*sizeof(Quantum);
905 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
906 for ( ; x < (ssize_t) clone_info->columns; x++)
907 {
908 if (clone_info->type != DiskCache)
909 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
910 blob,length);
911 else
912 {
913 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
914 if ((MagickSizeType) count != length)
915 {
916 status=MagickFalse;
917 break;
cristye04362f2012-04-23 15:33:05 +0000918 }
cristy888e6132012-04-23 19:54:54 +0000919 }
920 clone_offset+=length;
921 }
cristye04362f2012-04-23 15:33:05 +0000922 }
cristy4c08aed2011-07-01 19:47:50 +0000923 }
cristyed231572011-07-14 02:18:59 +0000924 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000925 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
926 for ( ; y < (ssize_t) clone_info->rows; y++)
927 {
928 /*
cristy9e0719b2011-12-29 03:45:45 +0000929 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000930 */
931 for (x=0; x < (ssize_t) clone_info->columns; x++)
932 {
933 if (clone_info->type != DiskCache)
934 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
935 length);
936 else
937 {
938 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
939 if ((MagickSizeType) count != length)
940 {
941 status=MagickFalse;
942 break;
943 }
944 }
945 clone_offset+=length;
946 }
947 }
cristy9e0719b2011-12-29 03:45:45 +0000948 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000949 (clone_info->metacontent_extent != 0))
950 {
951 /*
952 Clone metacontent.
953 */
954 for (y=0; y < (ssize_t) cache_info->rows; y++)
955 {
956 for (x=0; x < (ssize_t) cache_info->columns; x++)
957 {
958 /*
959 Read a set of metacontent.
960 */
961 length=cache_info->metacontent_extent;
962 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000963 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000964 else
965 {
cristyfd24a062012-01-02 14:46:34 +0000966 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000967 if ((MagickSizeType) count != length)
968 {
969 status=MagickFalse;
970 break;
971 }
972 }
973 cache_offset+=length;
974 if ((y < (ssize_t) clone_info->rows) &&
975 (x < (ssize_t) clone_info->columns))
976 {
977 /*
978 Write a set of metacontent.
979 */
980 length=clone_info->metacontent_extent;
981 if (clone_info->type != DiskCache)
982 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000983 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000984 else
985 {
cristyfd24a062012-01-02 14:46:34 +0000986 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000987 if ((MagickSizeType) count != length)
988 {
989 status=MagickFalse;
990 break;
991 }
992 }
993 clone_offset+=length;
994 }
995 }
996 length=clone_info->metacontent_extent;
997 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
998 for ( ; x < (ssize_t) clone_info->columns; x++)
999 {
1000 /*
cristy9e0719b2011-12-29 03:45:45 +00001001 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001002 */
1003 if (clone_info->type != DiskCache)
1004 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1005 blob,length);
1006 else
1007 {
cristy208b1002011-08-07 18:51:50 +00001008 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001009 if ((MagickSizeType) count != length)
1010 {
1011 status=MagickFalse;
1012 break;
1013 }
1014 }
1015 clone_offset+=length;
1016 }
1017 }
cristyac245f82012-05-05 17:13:57 +00001018 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001019 {
cristye04362f2012-04-23 15:33:05 +00001020 /*
1021 Set remaining rows as undefined.
1022 */
cristy888e6132012-04-23 19:54:54 +00001023 length=clone_info->metacontent_extent;
1024 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1025 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001026 {
cristy888e6132012-04-23 19:54:54 +00001027 for (x=0; x < (ssize_t) clone_info->columns; x++)
1028 {
1029 if (clone_info->type != DiskCache)
1030 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1031 blob,length);
1032 else
1033 {
1034 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1035 blob);
1036 if ((MagickSizeType) count != length)
1037 {
1038 status=MagickFalse;
1039 break;
1040 }
1041 }
1042 clone_offset+=length;
1043 }
cristye04362f2012-04-23 15:33:05 +00001044 }
cristy4c08aed2011-07-01 19:47:50 +00001045 }
cristy4c08aed2011-07-01 19:47:50 +00001046 }
1047 if (clone_info->type == DiskCache)
1048 (void) ClosePixelCacheOnDisk(clone_info);
1049 if (cache_info->type == DiskCache)
1050 (void) ClosePixelCacheOnDisk(cache_info);
1051 blob=(unsigned char *) RelinquishMagickMemory(blob);
1052 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001053}
1054
1055static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1056 CacheInfo *cache_info,ExceptionInfo *exception)
1057{
cristy3dfccb22011-12-28 21:47:20 +00001058 PixelChannelMap
1059 *p,
1060 *q;
1061
cristy5a7fbfb2010-11-06 16:10:59 +00001062 if (cache_info->type == PingCache)
1063 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001064 p=cache_info->channel_map;
1065 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001066 if ((cache_info->columns == clone_info->columns) &&
1067 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001068 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001069 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001070 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001071 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1072 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001073}
1074
1075/*
1076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1077% %
1078% %
1079% %
1080+ C l o n e P i x e l C a c h e M e t h o d s %
1081% %
1082% %
1083% %
1084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1085%
1086% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1087% another.
1088%
1089% The format of the ClonePixelCacheMethods() method is:
1090%
1091% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1092%
1093% A description of each parameter follows:
1094%
1095% o clone: Specifies a pointer to a Cache structure.
1096%
1097% o cache: the pixel cache.
1098%
1099*/
cristya6577ff2011-09-02 19:54:26 +00001100MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001101{
1102 CacheInfo
1103 *cache_info,
1104 *source_info;
1105
1106 assert(clone != (Cache) NULL);
1107 source_info=(CacheInfo *) clone;
1108 assert(source_info->signature == MagickSignature);
1109 if (source_info->debug != MagickFalse)
1110 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1111 source_info->filename);
1112 assert(cache != (Cache) NULL);
1113 cache_info=(CacheInfo *) cache;
1114 assert(cache_info->signature == MagickSignature);
1115 source_info->methods=cache_info->methods;
1116}
1117
1118/*
1119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1120% %
1121% %
1122% %
1123+ D e s t r o y I m a g e P i x e l C a c h e %
1124% %
1125% %
1126% %
1127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1128%
1129% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1130%
1131% The format of the DestroyImagePixelCache() method is:
1132%
1133% void DestroyImagePixelCache(Image *image)
1134%
1135% A description of each parameter follows:
1136%
1137% o image: the image.
1138%
1139*/
1140static void DestroyImagePixelCache(Image *image)
1141{
1142 assert(image != (Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 if (image->debug != MagickFalse)
1145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1146 if (image->cache == (void *) NULL)
1147 return;
1148 image->cache=DestroyPixelCache(image->cache);
1149}
1150
1151/*
1152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1153% %
1154% %
1155% %
1156+ D e s t r o y I m a g e P i x e l s %
1157% %
1158% %
1159% %
1160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1161%
1162% DestroyImagePixels() deallocates memory associated with the pixel cache.
1163%
1164% The format of the DestroyImagePixels() method is:
1165%
1166% void DestroyImagePixels(Image *image)
1167%
1168% A description of each parameter follows:
1169%
1170% o image: the image.
1171%
1172*/
1173MagickExport void DestroyImagePixels(Image *image)
1174{
1175 CacheInfo
1176 *cache_info;
1177
1178 assert(image != (const Image *) NULL);
1179 assert(image->signature == MagickSignature);
1180 if (image->debug != MagickFalse)
1181 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1182 assert(image->cache != (Cache) NULL);
1183 cache_info=(CacheInfo *) image->cache;
1184 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001185 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1186 {
1187 cache_info->methods.destroy_pixel_handler(image);
1188 return;
1189 }
cristy2036f5c2010-09-19 21:18:17 +00001190 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001191}
1192
1193/*
1194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1195% %
1196% %
1197% %
1198+ D e s t r o y P i x e l C a c h e %
1199% %
1200% %
1201% %
1202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203%
1204% DestroyPixelCache() deallocates memory associated with the pixel cache.
1205%
1206% The format of the DestroyPixelCache() method is:
1207%
1208% Cache DestroyPixelCache(Cache cache)
1209%
1210% A description of each parameter follows:
1211%
1212% o cache: the pixel cache.
1213%
1214*/
1215
1216static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1217{
1218 switch (cache_info->type)
1219 {
1220 case MemoryCache:
1221 {
1222 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001223 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001224 cache_info->pixels);
1225 else
cristy4c08aed2011-07-01 19:47:50 +00001226 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001227 (size_t) cache_info->length);
1228 RelinquishMagickResource(MemoryResource,cache_info->length);
1229 break;
1230 }
1231 case MapCache:
1232 {
cristy4c08aed2011-07-01 19:47:50 +00001233 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001234 cache_info->length);
1235 RelinquishMagickResource(MapResource,cache_info->length);
1236 }
1237 case DiskCache:
1238 {
1239 if (cache_info->file != -1)
1240 (void) ClosePixelCacheOnDisk(cache_info);
1241 RelinquishMagickResource(DiskResource,cache_info->length);
1242 break;
1243 }
1244 default:
1245 break;
1246 }
1247 cache_info->type=UndefinedCache;
1248 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001249 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001250}
1251
cristya6577ff2011-09-02 19:54:26 +00001252MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001253{
1254 CacheInfo
1255 *cache_info;
1256
cristy3ed852e2009-09-05 21:47:34 +00001257 assert(cache != (Cache) NULL);
1258 cache_info=(CacheInfo *) cache;
1259 assert(cache_info->signature == MagickSignature);
1260 if (cache_info->debug != MagickFalse)
1261 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1262 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001263 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001264 cache_info->reference_count--;
1265 if (cache_info->reference_count != 0)
1266 {
cristyf84a1932010-01-03 18:00:18 +00001267 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001268 return((Cache) NULL);
1269 }
cristyf84a1932010-01-03 18:00:18 +00001270 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001271 if (cache_info->debug != MagickFalse)
1272 {
1273 char
1274 message[MaxTextExtent];
1275
cristyb51dff52011-05-19 16:55:47 +00001276 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001277 cache_info->filename);
1278 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1279 }
cristyc2e1bdd2009-09-10 23:43:34 +00001280 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1281 (cache_info->type != DiskCache)))
1282 RelinquishPixelCachePixels(cache_info);
1283 else
1284 {
1285 RelinquishPixelCachePixels(cache_info);
1286 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1287 }
cristy3ed852e2009-09-05 21:47:34 +00001288 *cache_info->cache_filename='\0';
1289 if (cache_info->nexus_info != (NexusInfo **) NULL)
1290 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1291 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001292 if (cache_info->random_info != (RandomInfo *) NULL)
1293 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001294 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1295 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1296 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1297 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001298 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001299 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001300 cache=(Cache) NULL;
1301 return(cache);
1302}
1303
1304/*
1305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1306% %
1307% %
1308% %
1309+ D e s t r o y P i x e l C a c h e N e x u s %
1310% %
1311% %
1312% %
1313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1314%
1315% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1316%
1317% The format of the DestroyPixelCacheNexus() method is:
1318%
1319% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001320% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001321%
1322% A description of each parameter follows:
1323%
1324% o nexus_info: the nexus to destroy.
1325%
1326% o number_threads: the number of nexus threads.
1327%
1328*/
1329
1330static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1331{
1332 if (nexus_info->mapped == MagickFalse)
cristy64c3edf2012-04-13 18:50:13 +00001333 (void) RelinquishMagickMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001334 else
1335 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001336 nexus_info->cache=(Quantum *) NULL;
1337 nexus_info->pixels=(Quantum *) NULL;
1338 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001339 nexus_info->length=0;
1340 nexus_info->mapped=MagickFalse;
1341}
1342
cristya6577ff2011-09-02 19:54:26 +00001343MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001344 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001345{
cristybb503372010-05-27 20:51:26 +00001346 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001347 i;
1348
1349 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001350 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001351 {
cristy4c08aed2011-07-01 19:47:50 +00001352 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001353 RelinquishCacheNexusPixels(nexus_info[i]);
1354 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001355 }
cristye5f87c82012-02-14 12:44:17 +00001356 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001357 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001358 return(nexus_info);
1359}
1360
1361/*
1362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1363% %
1364% %
1365% %
cristy4c08aed2011-07-01 19:47:50 +00001366% 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 +00001367% %
1368% %
1369% %
1370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371%
cristy4c08aed2011-07-01 19:47:50 +00001372% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1373% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1374% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001375%
cristy4c08aed2011-07-01 19:47:50 +00001376% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001377%
cristy4c08aed2011-07-01 19:47:50 +00001378% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001379%
1380% A description of each parameter follows:
1381%
1382% o image: the image.
1383%
1384*/
cristy4c08aed2011-07-01 19:47:50 +00001385MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001386{
1387 CacheInfo
1388 *cache_info;
1389
cristy5c9e6f22010-09-17 17:31:01 +00001390 const int
1391 id = GetOpenMPThreadId();
1392
cristy4c08aed2011-07-01 19:47:50 +00001393 void
1394 *metacontent;
1395
cristye7cc7cf2010-09-21 13:26:47 +00001396 assert(image != (const Image *) NULL);
1397 assert(image->signature == MagickSignature);
1398 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001399 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001400 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001401 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1402 (GetAuthenticMetacontentFromHandler) NULL)
1403 {
1404 metacontent=cache_info->methods.
1405 get_authentic_metacontent_from_handler(image);
1406 return(metacontent);
1407 }
cristy6ebe97c2010-07-03 01:17:28 +00001408 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001409 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1410 cache_info->nexus_info[id]);
1411 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001412}
1413
1414/*
1415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416% %
1417% %
1418% %
cristy4c08aed2011-07-01 19:47:50 +00001419+ 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 +00001420% %
1421% %
1422% %
1423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1424%
cristy4c08aed2011-07-01 19:47:50 +00001425% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1426% with the last call to QueueAuthenticPixelsCache() or
1427% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001428%
cristy4c08aed2011-07-01 19:47:50 +00001429% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001430%
cristy4c08aed2011-07-01 19:47:50 +00001431% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001432%
1433% A description of each parameter follows:
1434%
1435% o image: the image.
1436%
1437*/
cristy4c08aed2011-07-01 19:47:50 +00001438static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001439{
1440 CacheInfo
1441 *cache_info;
1442
cristy2036f5c2010-09-19 21:18:17 +00001443 const int
1444 id = GetOpenMPThreadId();
1445
cristy4c08aed2011-07-01 19:47:50 +00001446 void
1447 *metacontent;
1448
cristy3ed852e2009-09-05 21:47:34 +00001449 assert(image != (const Image *) NULL);
1450 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001451 assert(image->cache != (Cache) NULL);
1452 cache_info=(CacheInfo *) image->cache;
1453 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001454 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001455 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1456 cache_info->nexus_info[id]);
1457 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001458}
1459
1460/*
1461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1462% %
1463% %
1464% %
1465+ 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 %
1466% %
1467% %
1468% %
1469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1470%
1471% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1472% disk pixel cache as defined by the geometry parameters. A pointer to the
1473% pixels is returned if the pixels are transferred, otherwise a NULL is
1474% returned.
1475%
1476% The format of the GetAuthenticPixelCacheNexus() method is:
1477%
cristy4c08aed2011-07-01 19:47:50 +00001478% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001479% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001480% NexusInfo *nexus_info,ExceptionInfo *exception)
1481%
1482% A description of each parameter follows:
1483%
1484% o image: the image.
1485%
1486% o x,y,columns,rows: These values define the perimeter of a region of
1487% pixels.
1488%
1489% o nexus_info: the cache nexus to return.
1490%
1491% o exception: return any errors or warnings in this structure.
1492%
1493*/
1494
cristy7f69b802012-05-08 16:39:59 +00001495static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001496 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001497{
cristy4c08aed2011-07-01 19:47:50 +00001498 MagickBooleanType
1499 status;
1500
cristy3ed852e2009-09-05 21:47:34 +00001501 MagickOffsetType
1502 offset;
1503
cristy73724512010-04-12 14:43:14 +00001504 if (cache_info->type == PingCache)
1505 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001506 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1507 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001508 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001509 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001510 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001511}
1512
cristya6577ff2011-09-02 19:54:26 +00001513MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001514 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001515 NexusInfo *nexus_info,ExceptionInfo *exception)
1516{
1517 CacheInfo
1518 *cache_info;
1519
cristy4c08aed2011-07-01 19:47:50 +00001520 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001521 *q;
cristy3ed852e2009-09-05 21:47:34 +00001522
1523 /*
1524 Transfer pixels from the cache.
1525 */
1526 assert(image != (Image *) NULL);
1527 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001528 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1529 exception);
cristyacd2ed22011-08-30 01:44:23 +00001530 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001531 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001532 cache_info=(CacheInfo *) image->cache;
1533 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001534 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001535 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001536 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001537 return((Quantum *) NULL);
1538 if (cache_info->metacontent_extent != 0)
1539 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1540 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001541 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001542}
1543
1544/*
1545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546% %
1547% %
1548% %
1549+ 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 %
1550% %
1551% %
1552% %
1553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1554%
1555% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1556% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1557%
1558% The format of the GetAuthenticPixelsFromCache() method is:
1559%
cristy4c08aed2011-07-01 19:47:50 +00001560% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001561%
1562% A description of each parameter follows:
1563%
1564% o image: the image.
1565%
1566*/
cristy4c08aed2011-07-01 19:47:50 +00001567static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001568{
1569 CacheInfo
1570 *cache_info;
1571
cristy5c9e6f22010-09-17 17:31:01 +00001572 const int
1573 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001574
cristye7cc7cf2010-09-21 13:26:47 +00001575 assert(image != (const Image *) NULL);
1576 assert(image->signature == MagickSignature);
1577 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001578 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001579 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001580 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001581 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001582}
1583
1584/*
1585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586% %
1587% %
1588% %
1589% G e t A u t h e n t i c P i x e l Q u e u e %
1590% %
1591% %
1592% %
1593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594%
cristy4c08aed2011-07-01 19:47:50 +00001595% GetAuthenticPixelQueue() returns the authentic pixels associated
1596% corresponding with the last call to QueueAuthenticPixels() or
1597% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001598%
1599% The format of the GetAuthenticPixelQueue() method is:
1600%
cristy4c08aed2011-07-01 19:47:50 +00001601% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001602%
1603% A description of each parameter follows:
1604%
1605% o image: the image.
1606%
1607*/
cristy4c08aed2011-07-01 19:47:50 +00001608MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001609{
1610 CacheInfo
1611 *cache_info;
1612
cristy2036f5c2010-09-19 21:18:17 +00001613 const int
1614 id = GetOpenMPThreadId();
1615
cristy3ed852e2009-09-05 21:47:34 +00001616 assert(image != (const Image *) NULL);
1617 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001618 assert(image->cache != (Cache) NULL);
1619 cache_info=(CacheInfo *) image->cache;
1620 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001621 if (cache_info->methods.get_authentic_pixels_from_handler !=
1622 (GetAuthenticPixelsFromHandler) NULL)
1623 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001624 assert(id < (int) cache_info->number_threads);
1625 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001626}
1627
1628/*
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630% %
1631% %
1632% %
1633% G e t A u t h e n t i c P i x e l s %
1634% %
1635% %
cristy4c08aed2011-07-01 19:47:50 +00001636% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001637%
1638% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001639% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001640% representing the region is returned, otherwise NULL is returned.
1641%
1642% The returned pointer may point to a temporary working copy of the pixels
1643% or it may point to the original pixels in memory. Performance is maximized
1644% if the selected region is part of one row, or one or more full rows, since
1645% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001646% if the image is in memory, or in a memory-mapped file. The returned pointer
1647% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001648%
1649% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001650% Quantum. If the image has corresponding metacontent,call
1651% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1652% meta-content corresponding to the region. Once the Quantum array has
1653% been updated, the changes must be saved back to the underlying image using
1654% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001655%
1656% The format of the GetAuthenticPixels() method is:
1657%
cristy4c08aed2011-07-01 19:47:50 +00001658% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001659% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001660% ExceptionInfo *exception)
1661%
1662% A description of each parameter follows:
1663%
1664% o image: the image.
1665%
1666% o x,y,columns,rows: These values define the perimeter of a region of
1667% pixels.
1668%
1669% o exception: return any errors or warnings in this structure.
1670%
1671*/
cristy4c08aed2011-07-01 19:47:50 +00001672MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001673 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001674 ExceptionInfo *exception)
1675{
1676 CacheInfo
1677 *cache_info;
1678
cristy2036f5c2010-09-19 21:18:17 +00001679 const int
1680 id = GetOpenMPThreadId();
1681
cristy4c08aed2011-07-01 19:47:50 +00001682 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001683 *q;
cristy4c08aed2011-07-01 19:47:50 +00001684
cristy3ed852e2009-09-05 21:47:34 +00001685 assert(image != (Image *) NULL);
1686 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001687 assert(image->cache != (Cache) NULL);
1688 cache_info=(CacheInfo *) image->cache;
1689 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001690 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001691 (GetAuthenticPixelsHandler) NULL)
1692 {
cristyacd2ed22011-08-30 01:44:23 +00001693 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1694 exception);
1695 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001696 }
cristy2036f5c2010-09-19 21:18:17 +00001697 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001698 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001699 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001700 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001701}
1702
1703/*
1704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1705% %
1706% %
1707% %
1708+ G e t A u t h e n t i c P i x e l s C a c h e %
1709% %
1710% %
1711% %
1712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1713%
1714% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1715% as defined by the geometry parameters. A pointer to the pixels is returned
1716% if the pixels are transferred, otherwise a NULL is returned.
1717%
1718% The format of the GetAuthenticPixelsCache() method is:
1719%
cristy4c08aed2011-07-01 19:47:50 +00001720% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001721% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001722% ExceptionInfo *exception)
1723%
1724% A description of each parameter follows:
1725%
1726% o image: the image.
1727%
1728% o x,y,columns,rows: These values define the perimeter of a region of
1729% pixels.
1730%
1731% o exception: return any errors or warnings in this structure.
1732%
1733*/
cristy4c08aed2011-07-01 19:47:50 +00001734static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001735 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001736 ExceptionInfo *exception)
1737{
1738 CacheInfo
1739 *cache_info;
1740
cristy5c9e6f22010-09-17 17:31:01 +00001741 const int
1742 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001743
cristy4c08aed2011-07-01 19:47:50 +00001744 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001745 *q;
cristy4c08aed2011-07-01 19:47:50 +00001746
cristye7cc7cf2010-09-21 13:26:47 +00001747 assert(image != (const Image *) NULL);
1748 assert(image->signature == MagickSignature);
1749 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001750 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001751 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001752 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001753 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001754 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001755 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001756 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001757 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001758}
1759
1760/*
1761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762% %
1763% %
1764% %
1765+ G e t I m a g e E x t e n t %
1766% %
1767% %
1768% %
1769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1770%
cristy4c08aed2011-07-01 19:47:50 +00001771% GetImageExtent() returns the extent of the pixels associated corresponding
1772% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001773%
1774% The format of the GetImageExtent() method is:
1775%
1776% MagickSizeType GetImageExtent(const Image *image)
1777%
1778% A description of each parameter follows:
1779%
1780% o image: the image.
1781%
1782*/
1783MagickExport MagickSizeType GetImageExtent(const Image *image)
1784{
1785 CacheInfo
1786 *cache_info;
1787
cristy5c9e6f22010-09-17 17:31:01 +00001788 const int
1789 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001790
cristy3ed852e2009-09-05 21:47:34 +00001791 assert(image != (Image *) NULL);
1792 assert(image->signature == MagickSignature);
1793 if (image->debug != MagickFalse)
1794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1795 assert(image->cache != (Cache) NULL);
1796 cache_info=(CacheInfo *) image->cache;
1797 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001798 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001799 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001800}
1801
1802/*
1803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1804% %
1805% %
1806% %
1807+ G e t I m a g e P i x e l C a c h e %
1808% %
1809% %
1810% %
1811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1812%
1813% GetImagePixelCache() ensures that there is only a single reference to the
1814% pixel cache to be modified, updating the provided cache pointer to point to
1815% a clone of the original pixel cache if necessary.
1816%
1817% The format of the GetImagePixelCache method is:
1818%
1819% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1820% ExceptionInfo *exception)
1821%
1822% A description of each parameter follows:
1823%
1824% o image: the image.
1825%
1826% o clone: any value other than MagickFalse clones the cache pixels.
1827%
1828% o exception: return any errors or warnings in this structure.
1829%
1830*/
cristyaf894d72011-08-06 23:03:10 +00001831
cristyf1832792012-05-08 18:38:18 +00001832static inline MagickBooleanType ValidatePixelCacheMorphology(
1833 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001834{
cristyf1832792012-05-08 18:38:18 +00001835 const CacheInfo
1836 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001837
cristyf1832792012-05-08 18:38:18 +00001838 const PixelChannelMap
1839 *restrict p,
1840 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001841
cristy3ed852e2009-09-05 21:47:34 +00001842 /*
1843 Does the image match the pixel cache morphology?
1844 */
1845 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001846 p=image->channel_map;
1847 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001848 if ((image->storage_class != cache_info->storage_class) ||
1849 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001850 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001851 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001852 (image->columns != cache_info->columns) ||
1853 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001854 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001855 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001856 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001857 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001858 return(MagickFalse);
1859 return(MagickTrue);
1860}
1861
cristycd01fae2011-08-06 23:52:42 +00001862static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1863 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001864{
1865 CacheInfo
1866 *cache_info;
1867
cristy3ed852e2009-09-05 21:47:34 +00001868 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001869 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001870 status;
1871
cristy50a10922010-02-15 18:35:25 +00001872 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001873 cpu_throttle = 0,
1874 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001875 time_limit = 0;
1876
cristy1ea34962010-07-01 19:49:21 +00001877 static time_t
cristy208b1002011-08-07 18:51:50 +00001878 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001879
cristyc4f9f132010-03-04 18:50:01 +00001880 status=MagickTrue;
1881 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001882 if (cpu_throttle == 0)
1883 {
1884 char
1885 *limit;
1886
1887 /*
1888 Set CPU throttle in milleseconds.
1889 */
1890 cpu_throttle=MagickResourceInfinity;
1891 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1892 if (limit == (char *) NULL)
1893 limit=GetPolicyValue("throttle");
1894 if (limit != (char *) NULL)
1895 {
1896 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1897 limit=DestroyString(limit);
1898 }
1899 }
1900 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1901 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001902 if (time_limit == 0)
1903 {
cristy6ebe97c2010-07-03 01:17:28 +00001904 /*
1905 Set the exire time in seconds.
1906 */
cristy1ea34962010-07-01 19:49:21 +00001907 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001908 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001909 }
1910 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001911 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001912 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001913 assert(image->cache != (Cache) NULL);
1914 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001915 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001916 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001917 {
cristyceb55ee2010-11-06 16:05:49 +00001918 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001919 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001920 {
cristyceb55ee2010-11-06 16:05:49 +00001921 Image
1922 clone_image;
1923
1924 CacheInfo
1925 *clone_info;
1926
1927 /*
1928 Clone pixel cache.
1929 */
1930 clone_image=(*image);
1931 clone_image.semaphore=AllocateSemaphoreInfo();
1932 clone_image.reference_count=1;
1933 clone_image.cache=ClonePixelCache(cache_info);
1934 clone_info=(CacheInfo *) clone_image.cache;
1935 status=OpenPixelCache(&clone_image,IOMode,exception);
1936 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001937 {
cristy5a7fbfb2010-11-06 16:10:59 +00001938 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001939 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001940 if (status != MagickFalse)
1941 {
cristy979bf772011-08-08 00:04:15 +00001942 if (cache_info->mode == ReadMode)
1943 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001944 destroy=MagickTrue;
1945 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001946 }
1947 }
cristyceb55ee2010-11-06 16:05:49 +00001948 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001949 }
cristyceb55ee2010-11-06 16:05:49 +00001950 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001951 }
cristy4320e0e2009-09-10 15:00:08 +00001952 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001953 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001954 if (status != MagickFalse)
1955 {
1956 /*
1957 Ensure the image matches the pixel cache morphology.
1958 */
1959 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001960 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001961 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001962 {
1963 status=OpenPixelCache(image,IOMode,exception);
1964 cache_info=(CacheInfo *) image->cache;
1965 if (cache_info->type == DiskCache)
1966 (void) ClosePixelCacheOnDisk(cache_info);
1967 }
cristy3ed852e2009-09-05 21:47:34 +00001968 }
cristyf84a1932010-01-03 18:00:18 +00001969 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001970 if (status == MagickFalse)
1971 return((Cache) NULL);
1972 return(image->cache);
1973}
1974
1975/*
1976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1977% %
1978% %
1979% %
1980% G e t O n e A u t h e n t i c P i x e l %
1981% %
1982% %
1983% %
1984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985%
1986% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1987% location. The image background color is returned if an error occurs.
1988%
1989% The format of the GetOneAuthenticPixel() method is:
1990%
cristybb503372010-05-27 20:51:26 +00001991% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00001992% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001993%
1994% A description of each parameter follows:
1995%
1996% o image: the image.
1997%
1998% o x,y: These values define the location of the pixel to return.
1999%
2000% o pixel: return a pixel at the specified (x,y) location.
2001%
2002% o exception: return any errors or warnings in this structure.
2003%
2004*/
cristyacbbb7c2010-06-30 18:56:48 +00002005MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002006 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002007{
2008 CacheInfo
2009 *cache_info;
2010
cristy4c08aed2011-07-01 19:47:50 +00002011 register Quantum
2012 *q;
cristy2036f5c2010-09-19 21:18:17 +00002013
cristy2ed42f62011-10-02 19:49:57 +00002014 register ssize_t
2015 i;
2016
cristy3ed852e2009-09-05 21:47:34 +00002017 assert(image != (Image *) NULL);
2018 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002019 assert(image->cache != (Cache) NULL);
2020 cache_info=(CacheInfo *) image->cache;
2021 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002022 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002023 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2024 (GetOneAuthenticPixelFromHandler) NULL)
2025 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2026 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002027 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2028 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002029 {
cristy9e0719b2011-12-29 03:45:45 +00002030 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2031 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2032 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2033 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2034 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002035 return(MagickFalse);
2036 }
2037 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2038 {
2039 PixelChannel
2040 channel;
2041
cristye2a912b2011-12-05 20:02:07 +00002042 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002043 pixel[channel]=q[i];
2044 }
cristy2036f5c2010-09-19 21:18:17 +00002045 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002046}
2047
2048/*
2049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2050% %
2051% %
2052% %
2053+ 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 %
2054% %
2055% %
2056% %
2057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2058%
2059% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2060% location. The image background color is returned if an error occurs.
2061%
2062% The format of the GetOneAuthenticPixelFromCache() method is:
2063%
2064% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002065% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002066% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002067%
2068% A description of each parameter follows:
2069%
2070% o image: the image.
2071%
2072% o x,y: These values define the location of the pixel to return.
2073%
2074% o pixel: return a pixel at the specified (x,y) location.
2075%
2076% o exception: return any errors or warnings in this structure.
2077%
2078*/
2079static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002080 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002081{
cristy098f78c2010-09-23 17:28:44 +00002082 CacheInfo
2083 *cache_info;
2084
2085 const int
2086 id = GetOpenMPThreadId();
2087
cristy4c08aed2011-07-01 19:47:50 +00002088 register Quantum
2089 *q;
cristy3ed852e2009-09-05 21:47:34 +00002090
cristy2ed42f62011-10-02 19:49:57 +00002091 register ssize_t
2092 i;
2093
cristy0158a4b2010-09-20 13:59:45 +00002094 assert(image != (const Image *) NULL);
2095 assert(image->signature == MagickSignature);
2096 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002097 cache_info=(CacheInfo *) image->cache;
2098 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002099 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002100 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002101 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2102 exception);
2103 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002104 {
cristy9e0719b2011-12-29 03:45:45 +00002105 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2106 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2107 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2108 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2109 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002110 return(MagickFalse);
2111 }
2112 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2113 {
2114 PixelChannel
2115 channel;
2116
cristye2a912b2011-12-05 20:02:07 +00002117 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002118 pixel[channel]=q[i];
2119 }
cristy3ed852e2009-09-05 21:47:34 +00002120 return(MagickTrue);
2121}
2122
2123/*
2124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2125% %
2126% %
2127% %
cristy3ed852e2009-09-05 21:47:34 +00002128% G e t O n e V i r t u a l P i x e l %
2129% %
2130% %
2131% %
2132%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2133%
2134% GetOneVirtualPixel() returns a single virtual pixel at the specified
2135% (x,y) location. The image background color is returned if an error occurs.
2136% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2137%
2138% The format of the GetOneVirtualPixel() method is:
2139%
cristybb503372010-05-27 20:51:26 +00002140% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002141% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002142%
2143% A description of each parameter follows:
2144%
2145% o image: the image.
2146%
2147% o x,y: These values define the location of the pixel to return.
2148%
2149% o pixel: return a pixel at the specified (x,y) location.
2150%
2151% o exception: return any errors or warnings in this structure.
2152%
2153*/
2154MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002155 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002156{
cristy3ed852e2009-09-05 21:47:34 +00002157 CacheInfo
2158 *cache_info;
2159
cristy0158a4b2010-09-20 13:59:45 +00002160 const int
2161 id = GetOpenMPThreadId();
2162
cristy4c08aed2011-07-01 19:47:50 +00002163 const Quantum
2164 *p;
cristy2036f5c2010-09-19 21:18:17 +00002165
cristy2ed42f62011-10-02 19:49:57 +00002166 register ssize_t
2167 i;
2168
cristy3ed852e2009-09-05 21:47:34 +00002169 assert(image != (const Image *) NULL);
2170 assert(image->signature == MagickSignature);
2171 assert(image->cache != (Cache) NULL);
2172 cache_info=(CacheInfo *) image->cache;
2173 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002174 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002175 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2176 (GetOneVirtualPixelFromHandler) NULL)
2177 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2178 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002179 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002180 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002181 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002182 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002183 {
cristy9e0719b2011-12-29 03:45:45 +00002184 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2185 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2186 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2187 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2188 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002189 return(MagickFalse);
2190 }
2191 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2192 {
2193 PixelChannel
2194 channel;
2195
cristye2a912b2011-12-05 20:02:07 +00002196 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002197 pixel[channel]=p[i];
2198 }
cristy2036f5c2010-09-19 21:18:17 +00002199 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002200}
2201
2202/*
2203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204% %
2205% %
2206% %
2207+ 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 %
2208% %
2209% %
2210% %
2211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212%
2213% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2214% specified (x,y) location. The image background color is returned if an
2215% error occurs.
2216%
2217% The format of the GetOneVirtualPixelFromCache() method is:
2218%
2219% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002220% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002221% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002222%
2223% A description of each parameter follows:
2224%
2225% o image: the image.
2226%
2227% o virtual_pixel_method: the virtual pixel method.
2228%
2229% o x,y: These values define the location of the pixel to return.
2230%
2231% o pixel: return a pixel at the specified (x,y) location.
2232%
2233% o exception: return any errors or warnings in this structure.
2234%
2235*/
2236static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002237 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002238 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002239{
cristy0158a4b2010-09-20 13:59:45 +00002240 CacheInfo
2241 *cache_info;
2242
2243 const int
2244 id = GetOpenMPThreadId();
2245
cristy4c08aed2011-07-01 19:47:50 +00002246 const Quantum
2247 *p;
cristy3ed852e2009-09-05 21:47:34 +00002248
cristy2ed42f62011-10-02 19:49:57 +00002249 register ssize_t
2250 i;
2251
cristye7cc7cf2010-09-21 13:26:47 +00002252 assert(image != (const Image *) NULL);
2253 assert(image->signature == MagickSignature);
2254 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002255 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002256 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002257 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002258 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002259 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002260 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002261 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002262 {
cristy9e0719b2011-12-29 03:45:45 +00002263 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2264 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2265 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2266 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2267 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002268 return(MagickFalse);
2269 }
2270 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2271 {
2272 PixelChannel
2273 channel;
2274
cristye2a912b2011-12-05 20:02:07 +00002275 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002276 pixel[channel]=p[i];
2277 }
cristy3ed852e2009-09-05 21:47:34 +00002278 return(MagickTrue);
2279}
2280
2281/*
2282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2283% %
2284% %
2285% %
cristy3aa93752011-12-18 15:54:24 +00002286% G e t O n e V i r t u a l P i x e l I n f o %
2287% %
2288% %
2289% %
2290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2291%
2292% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2293% location. The image background color is returned if an error occurs. If
2294% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2295%
2296% The format of the GetOneVirtualPixelInfo() method is:
2297%
2298% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2299% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2300% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2301%
2302% A description of each parameter follows:
2303%
2304% o image: the image.
2305%
2306% o virtual_pixel_method: the virtual pixel method.
2307%
2308% o x,y: these values define the location of the pixel to return.
2309%
2310% o pixel: return a pixel at the specified (x,y) location.
2311%
2312% o exception: return any errors or warnings in this structure.
2313%
2314*/
2315MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2316 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2317 PixelInfo *pixel,ExceptionInfo *exception)
2318{
2319 CacheInfo
2320 *cache_info;
2321
2322 const int
2323 id = GetOpenMPThreadId();
2324
2325 register const Quantum
2326 *p;
2327
2328 assert(image != (const Image *) NULL);
2329 assert(image->signature == MagickSignature);
2330 assert(image->cache != (Cache) NULL);
2331 cache_info=(CacheInfo *) image->cache;
2332 assert(cache_info->signature == MagickSignature);
2333 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002334 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002335 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2336 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002337 if (p == (const Quantum *) NULL)
2338 return(MagickFalse);
2339 GetPixelInfoPixel(image,p,pixel);
2340 return(MagickTrue);
2341}
2342
2343/*
2344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2345% %
2346% %
2347% %
cristy3ed852e2009-09-05 21:47:34 +00002348+ G e t P i x e l C a c h e C o l o r s p a c e %
2349% %
2350% %
2351% %
2352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2353%
2354% GetPixelCacheColorspace() returns the class type of the pixel cache.
2355%
2356% The format of the GetPixelCacheColorspace() method is:
2357%
2358% Colorspace GetPixelCacheColorspace(Cache cache)
2359%
2360% A description of each parameter follows:
2361%
2362% o cache: the pixel cache.
2363%
2364*/
cristya6577ff2011-09-02 19:54:26 +00002365MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002366{
2367 CacheInfo
2368 *cache_info;
2369
2370 assert(cache != (Cache) NULL);
2371 cache_info=(CacheInfo *) cache;
2372 assert(cache_info->signature == MagickSignature);
2373 if (cache_info->debug != MagickFalse)
2374 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2375 cache_info->filename);
2376 return(cache_info->colorspace);
2377}
2378
2379/*
2380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2381% %
2382% %
2383% %
2384+ G e t P i x e l C a c h e M e t h o d s %
2385% %
2386% %
2387% %
2388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2389%
2390% GetPixelCacheMethods() initializes the CacheMethods structure.
2391%
2392% The format of the GetPixelCacheMethods() method is:
2393%
2394% void GetPixelCacheMethods(CacheMethods *cache_methods)
2395%
2396% A description of each parameter follows:
2397%
2398% o cache_methods: Specifies a pointer to a CacheMethods structure.
2399%
2400*/
cristya6577ff2011-09-02 19:54:26 +00002401MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002402{
2403 assert(cache_methods != (CacheMethods *) NULL);
2404 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2405 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2406 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002407 cache_methods->get_virtual_metacontent_from_handler=
2408 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002409 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2410 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002411 cache_methods->get_authentic_metacontent_from_handler=
2412 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002413 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2414 cache_methods->get_one_authentic_pixel_from_handler=
2415 GetOneAuthenticPixelFromCache;
2416 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2417 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2418 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2419}
2420
2421/*
2422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2423% %
2424% %
2425% %
2426+ G e t P i x e l C a c h e N e x u s E x t e n t %
2427% %
2428% %
2429% %
2430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2431%
cristy4c08aed2011-07-01 19:47:50 +00002432% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2433% corresponding with the last call to SetPixelCacheNexusPixels() or
2434% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002435%
2436% The format of the GetPixelCacheNexusExtent() method is:
2437%
2438% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2439% NexusInfo *nexus_info)
2440%
2441% A description of each parameter follows:
2442%
2443% o nexus_info: the nexus info.
2444%
2445*/
cristya6577ff2011-09-02 19:54:26 +00002446MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002447 NexusInfo *nexus_info)
2448{
2449 CacheInfo
2450 *cache_info;
2451
2452 MagickSizeType
2453 extent;
2454
cristy9f027d12011-09-21 01:17:17 +00002455 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002456 cache_info=(CacheInfo *) cache;
2457 assert(cache_info->signature == MagickSignature);
2458 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2459 if (extent == 0)
2460 return((MagickSizeType) cache_info->columns*cache_info->rows);
2461 return(extent);
2462}
2463
2464/*
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466% %
2467% %
2468% %
cristy4c08aed2011-07-01 19:47:50 +00002469+ 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 +00002470% %
2471% %
2472% %
2473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474%
cristy4c08aed2011-07-01 19:47:50 +00002475% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2476% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002477%
cristy4c08aed2011-07-01 19:47:50 +00002478% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002479%
cristy4c08aed2011-07-01 19:47:50 +00002480% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002481% NexusInfo *nexus_info)
2482%
2483% A description of each parameter follows:
2484%
2485% o cache: the pixel cache.
2486%
cristy4c08aed2011-07-01 19:47:50 +00002487% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002488%
2489*/
cristya6577ff2011-09-02 19:54:26 +00002490MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002491 NexusInfo *nexus_info)
2492{
2493 CacheInfo
2494 *cache_info;
2495
cristy9f027d12011-09-21 01:17:17 +00002496 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002497 cache_info=(CacheInfo *) cache;
2498 assert(cache_info->signature == MagickSignature);
2499 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002500 return((void *) NULL);
2501 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002502}
2503
2504/*
2505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2506% %
2507% %
2508% %
2509+ G e t P i x e l C a c h e N e x u s P i x e l s %
2510% %
2511% %
2512% %
2513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2514%
2515% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2516% cache nexus.
2517%
2518% The format of the GetPixelCacheNexusPixels() method is:
2519%
cristy4c08aed2011-07-01 19:47:50 +00002520% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002521% NexusInfo *nexus_info)
2522%
2523% A description of each parameter follows:
2524%
2525% o cache: the pixel cache.
2526%
2527% o nexus_info: the cache nexus to return the pixels.
2528%
2529*/
cristya6577ff2011-09-02 19:54:26 +00002530MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002531 NexusInfo *nexus_info)
2532{
2533 CacheInfo
2534 *cache_info;
2535
cristy9f027d12011-09-21 01:17:17 +00002536 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002537 cache_info=(CacheInfo *) cache;
2538 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002539 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002540 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002541 return(nexus_info->pixels);
2542}
2543
2544/*
2545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2546% %
2547% %
2548% %
cristy056ba772010-01-02 23:33:54 +00002549+ G e t P i x e l C a c h e P i x e l s %
2550% %
2551% %
2552% %
2553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2554%
2555% GetPixelCachePixels() returns the pixels associated with the specified image.
2556%
2557% The format of the GetPixelCachePixels() method is:
2558%
cristyf84a1932010-01-03 18:00:18 +00002559% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2560% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002561%
2562% A description of each parameter follows:
2563%
2564% o image: the image.
2565%
2566% o length: the pixel cache length.
2567%
cristyf84a1932010-01-03 18:00:18 +00002568% o exception: return any errors or warnings in this structure.
2569%
cristy056ba772010-01-02 23:33:54 +00002570*/
cristyd1dd6e42011-09-04 01:46:08 +00002571MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002572 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002573{
2574 CacheInfo
2575 *cache_info;
2576
2577 assert(image != (const Image *) NULL);
2578 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002579 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002580 assert(length != (MagickSizeType *) NULL);
2581 assert(exception != (ExceptionInfo *) NULL);
2582 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002583 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002584 assert(cache_info->signature == MagickSignature);
2585 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002586 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002587 return((void *) NULL);
2588 *length=cache_info->length;
2589 return((void *) cache_info->pixels);
2590}
2591
2592/*
2593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2594% %
2595% %
2596% %
cristyb32b90a2009-09-07 21:45:48 +00002597+ 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 +00002598% %
2599% %
2600% %
2601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2602%
2603% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2604%
2605% The format of the GetPixelCacheStorageClass() method is:
2606%
2607% ClassType GetPixelCacheStorageClass(Cache cache)
2608%
2609% A description of each parameter follows:
2610%
2611% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2612%
2613% o cache: the pixel cache.
2614%
2615*/
cristya6577ff2011-09-02 19:54:26 +00002616MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002617{
2618 CacheInfo
2619 *cache_info;
2620
2621 assert(cache != (Cache) NULL);
2622 cache_info=(CacheInfo *) cache;
2623 assert(cache_info->signature == MagickSignature);
2624 if (cache_info->debug != MagickFalse)
2625 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2626 cache_info->filename);
2627 return(cache_info->storage_class);
2628}
2629
2630/*
2631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2632% %
2633% %
2634% %
cristyb32b90a2009-09-07 21:45:48 +00002635+ G e t P i x e l C a c h e T i l e S i z e %
2636% %
2637% %
2638% %
2639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2640%
2641% GetPixelCacheTileSize() returns the pixel cache tile size.
2642%
2643% The format of the GetPixelCacheTileSize() method is:
2644%
cristybb503372010-05-27 20:51:26 +00002645% void GetPixelCacheTileSize(const Image *image,size_t *width,
2646% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002647%
2648% A description of each parameter follows:
2649%
2650% o image: the image.
2651%
2652% o width: the optimize cache tile width in pixels.
2653%
2654% o height: the optimize cache tile height in pixels.
2655%
2656*/
cristya6577ff2011-09-02 19:54:26 +00002657MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002658 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002659{
cristy4c08aed2011-07-01 19:47:50 +00002660 CacheInfo
2661 *cache_info;
2662
cristyb32b90a2009-09-07 21:45:48 +00002663 assert(image != (Image *) NULL);
2664 assert(image->signature == MagickSignature);
2665 if (image->debug != MagickFalse)
2666 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002667 cache_info=(CacheInfo *) image->cache;
2668 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002669 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002670 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002671 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002672 *height=(*width);
2673}
2674
2675/*
2676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2677% %
2678% %
2679% %
2680+ G e t P i x e l C a c h e T y p e %
2681% %
2682% %
2683% %
2684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2685%
2686% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2687%
2688% The format of the GetPixelCacheType() method is:
2689%
2690% CacheType GetPixelCacheType(const Image *image)
2691%
2692% A description of each parameter follows:
2693%
2694% o image: the image.
2695%
2696*/
cristya6577ff2011-09-02 19:54:26 +00002697MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002698{
2699 CacheInfo
2700 *cache_info;
2701
2702 assert(image != (Image *) NULL);
2703 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002704 assert(image->cache != (Cache) NULL);
2705 cache_info=(CacheInfo *) image->cache;
2706 assert(cache_info->signature == MagickSignature);
2707 return(cache_info->type);
2708}
2709
2710/*
2711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2712% %
2713% %
2714% %
cristy3ed852e2009-09-05 21:47:34 +00002715+ 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 %
2716% %
2717% %
2718% %
2719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2720%
2721% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2722% pixel cache. A virtual pixel is any pixel access that is outside the
2723% boundaries of the image cache.
2724%
2725% The format of the GetPixelCacheVirtualMethod() method is:
2726%
2727% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2728%
2729% A description of each parameter follows:
2730%
2731% o image: the image.
2732%
2733*/
cristyd1dd6e42011-09-04 01:46:08 +00002734MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002735{
2736 CacheInfo
2737 *cache_info;
2738
2739 assert(image != (Image *) NULL);
2740 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002741 assert(image->cache != (Cache) NULL);
2742 cache_info=(CacheInfo *) image->cache;
2743 assert(cache_info->signature == MagickSignature);
2744 return(cache_info->virtual_pixel_method);
2745}
2746
2747/*
2748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749% %
2750% %
2751% %
cristy4c08aed2011-07-01 19:47:50 +00002752+ 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 +00002753% %
2754% %
2755% %
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757%
cristy4c08aed2011-07-01 19:47:50 +00002758% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2759% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002760%
cristy4c08aed2011-07-01 19:47:50 +00002761% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002762%
cristy4c08aed2011-07-01 19:47:50 +00002763% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002764%
2765% A description of each parameter follows:
2766%
2767% o image: the image.
2768%
2769*/
cristy4c08aed2011-07-01 19:47:50 +00002770static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002771{
2772 CacheInfo
2773 *cache_info;
2774
cristy5c9e6f22010-09-17 17:31:01 +00002775 const int
2776 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002777
cristy4c08aed2011-07-01 19:47:50 +00002778 const void
2779 *metacontent;
2780
cristye7cc7cf2010-09-21 13:26:47 +00002781 assert(image != (const Image *) NULL);
2782 assert(image->signature == MagickSignature);
2783 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002784 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002785 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002786 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002787 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2788 cache_info->nexus_info[id]);
2789 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002790}
2791
2792/*
2793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2794% %
2795% %
2796% %
cristy4c08aed2011-07-01 19:47:50 +00002797+ 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 +00002798% %
2799% %
2800% %
2801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802%
cristy4c08aed2011-07-01 19:47:50 +00002803% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2804% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002805%
cristy4c08aed2011-07-01 19:47:50 +00002806% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002807%
cristy4c08aed2011-07-01 19:47:50 +00002808% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002809% NexusInfo *nexus_info)
2810%
2811% A description of each parameter follows:
2812%
2813% o cache: the pixel cache.
2814%
cristy4c08aed2011-07-01 19:47:50 +00002815% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002816%
2817*/
cristya6577ff2011-09-02 19:54:26 +00002818MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002819 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002820{
2821 CacheInfo
2822 *cache_info;
2823
cristye7cc7cf2010-09-21 13:26:47 +00002824 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002825 cache_info=(CacheInfo *) cache;
2826 assert(cache_info->signature == MagickSignature);
2827 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002828 return((void *) NULL);
2829 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002830}
2831
2832/*
2833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2834% %
2835% %
2836% %
cristy4c08aed2011-07-01 19:47:50 +00002837% 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 +00002838% %
2839% %
2840% %
2841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2842%
cristy4c08aed2011-07-01 19:47:50 +00002843% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2844% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2845% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002846%
cristy4c08aed2011-07-01 19:47:50 +00002847% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002848%
cristy4c08aed2011-07-01 19:47:50 +00002849% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002850%
2851% A description of each parameter follows:
2852%
2853% o image: the image.
2854%
2855*/
cristy4c08aed2011-07-01 19:47:50 +00002856MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002857{
2858 CacheInfo
2859 *cache_info;
2860
cristy2036f5c2010-09-19 21:18:17 +00002861 const int
2862 id = GetOpenMPThreadId();
2863
cristy4c08aed2011-07-01 19:47:50 +00002864 const void
2865 *metacontent;
2866
cristy3ed852e2009-09-05 21:47:34 +00002867 assert(image != (const Image *) NULL);
2868 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002869 assert(image->cache != (Cache) NULL);
2870 cache_info=(CacheInfo *) image->cache;
2871 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002872 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002873 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002874 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002875 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002876 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2877 cache_info->nexus_info[id]);
2878 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002879}
2880
2881/*
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883% %
2884% %
2885% %
2886+ 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 %
2887% %
2888% %
2889% %
2890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891%
2892% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2893% pixel cache as defined by the geometry parameters. A pointer to the pixels
2894% is returned if the pixels are transferred, otherwise a NULL is returned.
2895%
2896% The format of the GetVirtualPixelsFromNexus() method is:
2897%
cristy4c08aed2011-07-01 19:47:50 +00002898% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002899% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002900% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2901% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002902%
2903% A description of each parameter follows:
2904%
2905% o image: the image.
2906%
2907% o virtual_pixel_method: the virtual pixel method.
2908%
2909% o x,y,columns,rows: These values define the perimeter of a region of
2910% pixels.
2911%
2912% o nexus_info: the cache nexus to acquire.
2913%
2914% o exception: return any errors or warnings in this structure.
2915%
2916*/
2917
cristybb503372010-05-27 20:51:26 +00002918static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002919 DitherMatrix[64] =
2920 {
2921 0, 48, 12, 60, 3, 51, 15, 63,
2922 32, 16, 44, 28, 35, 19, 47, 31,
2923 8, 56, 4, 52, 11, 59, 7, 55,
2924 40, 24, 36, 20, 43, 27, 39, 23,
2925 2, 50, 14, 62, 1, 49, 13, 61,
2926 34, 18, 46, 30, 33, 17, 45, 29,
2927 10, 58, 6, 54, 9, 57, 5, 53,
2928 42, 26, 38, 22, 41, 25, 37, 21
2929 };
2930
cristybb503372010-05-27 20:51:26 +00002931static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002932{
cristybb503372010-05-27 20:51:26 +00002933 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002934 index;
2935
2936 index=x+DitherMatrix[x & 0x07]-32L;
2937 if (index < 0L)
2938 return(0L);
cristybb503372010-05-27 20:51:26 +00002939 if (index >= (ssize_t) columns)
2940 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002941 return(index);
2942}
2943
cristybb503372010-05-27 20:51:26 +00002944static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002945{
cristybb503372010-05-27 20:51:26 +00002946 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002947 index;
2948
2949 index=y+DitherMatrix[y & 0x07]-32L;
2950 if (index < 0L)
2951 return(0L);
cristybb503372010-05-27 20:51:26 +00002952 if (index >= (ssize_t) rows)
2953 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002954 return(index);
2955}
2956
cristybb503372010-05-27 20:51:26 +00002957static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002958{
2959 if (x < 0L)
2960 return(0L);
cristybb503372010-05-27 20:51:26 +00002961 if (x >= (ssize_t) columns)
2962 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002963 return(x);
2964}
2965
cristybb503372010-05-27 20:51:26 +00002966static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002967{
2968 if (y < 0L)
2969 return(0L);
cristybb503372010-05-27 20:51:26 +00002970 if (y >= (ssize_t) rows)
2971 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002972 return(y);
2973}
2974
cristybb503372010-05-27 20:51:26 +00002975static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002976{
cristybb503372010-05-27 20:51:26 +00002977 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002978}
2979
cristybb503372010-05-27 20:51:26 +00002980static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002981{
cristybb503372010-05-27 20:51:26 +00002982 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002983}
2984
cristybb503372010-05-27 20:51:26 +00002985static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2986 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002987{
2988 MagickModulo
2989 modulo;
2990
cristy6162bb42011-07-18 11:34:09 +00002991 /*
2992 Compute the remainder of dividing offset by extent. It returns not only
2993 the quotient (tile the offset falls in) but also the positive remainer
2994 within that tile such that 0 <= remainder < extent. This method is
2995 essentially a ldiv() using a floored modulo division rather than the
2996 normal default truncated modulo division.
2997 */
cristybb503372010-05-27 20:51:26 +00002998 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002999 if (offset < 0L)
3000 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003001 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003002 return(modulo);
3003}
3004
cristya6577ff2011-09-02 19:54:26 +00003005MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003006 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3007 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003008 ExceptionInfo *exception)
3009{
3010 CacheInfo
3011 *cache_info;
3012
3013 MagickOffsetType
3014 offset;
3015
3016 MagickSizeType
3017 length,
3018 number_pixels;
3019
3020 NexusInfo
3021 **virtual_nexus;
3022
cristy4c08aed2011-07-01 19:47:50 +00003023 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003024 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003025 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003026
3027 RectangleInfo
3028 region;
3029
cristy4c08aed2011-07-01 19:47:50 +00003030 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003031 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003032
cristy4c08aed2011-07-01 19:47:50 +00003033 register const void
3034 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003035
cristy4c08aed2011-07-01 19:47:50 +00003036 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003037 *restrict q;
3038
cristybb503372010-05-27 20:51:26 +00003039 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003040 i,
3041 u;
cristy3ed852e2009-09-05 21:47:34 +00003042
cristy4c08aed2011-07-01 19:47:50 +00003043 register unsigned char
3044 *restrict s;
3045
cristy105ba3c2011-07-18 02:28:38 +00003046 ssize_t
3047 v;
3048
cristy4c08aed2011-07-01 19:47:50 +00003049 void
cristy105ba3c2011-07-18 02:28:38 +00003050 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003051
cristy3ed852e2009-09-05 21:47:34 +00003052 /*
3053 Acquire pixels.
3054 */
cristye7cc7cf2010-09-21 13:26:47 +00003055 assert(image != (const Image *) NULL);
3056 assert(image->signature == MagickSignature);
3057 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003058 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003059 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003060 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003061 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003062 region.x=x;
3063 region.y=y;
3064 region.width=columns;
3065 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003066 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003067 if (pixels == (Quantum *) NULL)
3068 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003069 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003070 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3071 nexus_info->region.x;
3072 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3073 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003074 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3075 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003076 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3077 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003078 {
3079 MagickBooleanType
3080 status;
3081
3082 /*
3083 Pixel request is inside cache extents.
3084 */
cristy4c08aed2011-07-01 19:47:50 +00003085 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003086 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003087 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3088 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003089 return((const Quantum *) NULL);
3090 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003091 {
cristy4c08aed2011-07-01 19:47:50 +00003092 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003093 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003094 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003095 }
cristyacd2ed22011-08-30 01:44:23 +00003096 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003097 }
3098 /*
3099 Pixel request is outside cache extents.
3100 */
cristy4c08aed2011-07-01 19:47:50 +00003101 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003102 virtual_nexus=AcquirePixelCacheNexus(1);
3103 if (virtual_nexus == (NexusInfo **) NULL)
3104 {
cristy4c08aed2011-07-01 19:47:50 +00003105 if (virtual_nexus != (NexusInfo **) NULL)
3106 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003107 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003108 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003109 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003110 }
cristy105ba3c2011-07-18 02:28:38 +00003111 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3112 sizeof(*virtual_pixel));
3113 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003114 switch (virtual_pixel_method)
3115 {
cristy4c08aed2011-07-01 19:47:50 +00003116 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003117 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003118 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003119 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 case MaskVirtualPixelMethod:
3121 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003122 case EdgeVirtualPixelMethod:
3123 case CheckerTileVirtualPixelMethod:
3124 case HorizontalTileVirtualPixelMethod:
3125 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003126 {
cristy4c08aed2011-07-01 19:47:50 +00003127 if (cache_info->metacontent_extent != 0)
3128 {
cristy6162bb42011-07-18 11:34:09 +00003129 /*
3130 Acquire a metacontent buffer.
3131 */
cristya64b85d2011-09-14 01:02:31 +00003132 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003133 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003134 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003135 {
cristy4c08aed2011-07-01 19:47:50 +00003136 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3137 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003138 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003139 return((const Quantum *) NULL);
3140 }
cristy105ba3c2011-07-18 02:28:38 +00003141 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003142 cache_info->metacontent_extent);
3143 }
3144 switch (virtual_pixel_method)
3145 {
3146 case BlackVirtualPixelMethod:
3147 {
cristy30301712011-07-18 15:06:51 +00003148 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3149 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003150 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3151 break;
3152 }
3153 case GrayVirtualPixelMethod:
3154 {
cristy30301712011-07-18 15:06:51 +00003155 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003156 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3157 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003158 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3159 break;
3160 }
3161 case TransparentVirtualPixelMethod:
3162 {
cristy30301712011-07-18 15:06:51 +00003163 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3164 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003165 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3166 break;
3167 }
3168 case MaskVirtualPixelMethod:
3169 case WhiteVirtualPixelMethod:
3170 {
cristy30301712011-07-18 15:06:51 +00003171 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3172 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003173 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3174 break;
3175 }
3176 default:
3177 {
cristy9e0719b2011-12-29 03:45:45 +00003178 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3179 virtual_pixel);
3180 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3181 virtual_pixel);
3182 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3183 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003184 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3185 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003186 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3187 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003188 break;
3189 }
3190 }
cristy3ed852e2009-09-05 21:47:34 +00003191 break;
3192 }
3193 default:
cristy3ed852e2009-09-05 21:47:34 +00003194 break;
cristy3ed852e2009-09-05 21:47:34 +00003195 }
cristybb503372010-05-27 20:51:26 +00003196 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003197 {
cristybb503372010-05-27 20:51:26 +00003198 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003199 {
3200 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003201 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003202 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3203 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003204 {
3205 MagickModulo
3206 x_modulo,
3207 y_modulo;
3208
3209 /*
3210 Transfer a single pixel.
3211 */
3212 length=(MagickSizeType) 1;
3213 switch (virtual_pixel_method)
3214 {
cristy3ed852e2009-09-05 21:47:34 +00003215 default:
3216 {
3217 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003218 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003219 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003220 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003221 break;
3222 }
3223 case RandomVirtualPixelMethod:
3224 {
3225 if (cache_info->random_info == (RandomInfo *) NULL)
3226 cache_info->random_info=AcquireRandomInfo();
3227 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003228 RandomX(cache_info->random_info,cache_info->columns),
3229 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003230 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003231 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003232 break;
3233 }
3234 case DitherVirtualPixelMethod:
3235 {
3236 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003237 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003238 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003239 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003240 break;
3241 }
3242 case TileVirtualPixelMethod:
3243 {
3244 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3245 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3246 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003247 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003248 exception);
cristy4c08aed2011-07-01 19:47:50 +00003249 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003250 break;
3251 }
3252 case MirrorVirtualPixelMethod:
3253 {
3254 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3255 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003256 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003257 x_modulo.remainder-1L;
3258 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3259 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003260 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003261 y_modulo.remainder-1L;
3262 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003263 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003264 exception);
cristy4c08aed2011-07-01 19:47:50 +00003265 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003266 break;
3267 }
3268 case HorizontalTileEdgeVirtualPixelMethod:
3269 {
3270 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3271 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003272 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003273 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003274 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003275 break;
3276 }
3277 case VerticalTileEdgeVirtualPixelMethod:
3278 {
3279 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3280 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003281 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003282 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003283 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3284 break;
3285 }
3286 case BackgroundVirtualPixelMethod:
3287 case BlackVirtualPixelMethod:
3288 case GrayVirtualPixelMethod:
3289 case TransparentVirtualPixelMethod:
3290 case MaskVirtualPixelMethod:
3291 case WhiteVirtualPixelMethod:
3292 {
3293 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003294 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003295 break;
3296 }
3297 case EdgeVirtualPixelMethod:
3298 case CheckerTileVirtualPixelMethod:
3299 {
3300 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3301 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3302 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3303 {
3304 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003305 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003306 break;
3307 }
3308 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3309 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3310 exception);
3311 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3312 break;
3313 }
3314 case HorizontalTileVirtualPixelMethod:
3315 {
3316 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3317 {
3318 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003319 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003320 break;
3321 }
3322 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3323 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3324 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3325 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3326 exception);
3327 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3328 break;
3329 }
3330 case VerticalTileVirtualPixelMethod:
3331 {
3332 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3333 {
3334 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003335 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003336 break;
3337 }
3338 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3339 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3340 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3341 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3342 exception);
3343 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003344 break;
3345 }
3346 }
cristy4c08aed2011-07-01 19:47:50 +00003347 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003348 break;
cristyed231572011-07-14 02:18:59 +00003349 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003350 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003351 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003352 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003353 {
3354 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3355 s+=cache_info->metacontent_extent;
3356 }
cristy3ed852e2009-09-05 21:47:34 +00003357 continue;
3358 }
3359 /*
3360 Transfer a run of pixels.
3361 */
cristy4c08aed2011-07-01 19:47:50 +00003362 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3363 length,1UL,*virtual_nexus,exception);
3364 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003365 break;
cristy4c08aed2011-07-01 19:47:50 +00003366 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003367 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3368 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003369 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003370 {
cristy4c08aed2011-07-01 19:47:50 +00003371 (void) memcpy(s,r,(size_t) length);
3372 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003373 }
3374 }
3375 }
cristy4c08aed2011-07-01 19:47:50 +00003376 /*
3377 Free resources.
3378 */
cristy105ba3c2011-07-18 02:28:38 +00003379 if (virtual_metacontent != (void *) NULL)
3380 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003381 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3382 return(pixels);
3383}
3384
3385/*
3386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3387% %
3388% %
3389% %
3390+ G e t V i r t u a l P i x e l C a c h e %
3391% %
3392% %
3393% %
3394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3395%
3396% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3397% cache as defined by the geometry parameters. A pointer to the pixels
3398% is returned if the pixels are transferred, otherwise a NULL is returned.
3399%
3400% The format of the GetVirtualPixelCache() method is:
3401%
cristy4c08aed2011-07-01 19:47:50 +00003402% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003403% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3404% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003405% ExceptionInfo *exception)
3406%
3407% A description of each parameter follows:
3408%
3409% o image: the image.
3410%
3411% o virtual_pixel_method: the virtual pixel method.
3412%
3413% o x,y,columns,rows: These values define the perimeter of a region of
3414% pixels.
3415%
3416% o exception: return any errors or warnings in this structure.
3417%
3418*/
cristy4c08aed2011-07-01 19:47:50 +00003419static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003420 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3421 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003422{
3423 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003424 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003425
cristy5c9e6f22010-09-17 17:31:01 +00003426 const int
3427 id = GetOpenMPThreadId();
3428
cristy4c08aed2011-07-01 19:47:50 +00003429 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003430 *p;
cristy4c08aed2011-07-01 19:47:50 +00003431
cristye7cc7cf2010-09-21 13:26:47 +00003432 assert(image != (const Image *) NULL);
3433 assert(image->signature == MagickSignature);
3434 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003435 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003436 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003437 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003439 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003440 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003441}
3442
3443/*
3444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3445% %
3446% %
3447% %
3448% G e t V i r t u a l P i x e l Q u e u e %
3449% %
3450% %
3451% %
3452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3453%
cristy4c08aed2011-07-01 19:47:50 +00003454% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3455% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003456%
3457% The format of the GetVirtualPixelQueue() method is:
3458%
cristy4c08aed2011-07-01 19:47:50 +00003459% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003460%
3461% A description of each parameter follows:
3462%
3463% o image: the image.
3464%
3465*/
cristy4c08aed2011-07-01 19:47:50 +00003466MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003467{
3468 CacheInfo
3469 *cache_info;
3470
cristy2036f5c2010-09-19 21:18:17 +00003471 const int
3472 id = GetOpenMPThreadId();
3473
cristy3ed852e2009-09-05 21:47:34 +00003474 assert(image != (const Image *) NULL);
3475 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003476 assert(image->cache != (Cache) NULL);
3477 cache_info=(CacheInfo *) image->cache;
3478 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003479 if (cache_info->methods.get_virtual_pixels_handler !=
3480 (GetVirtualPixelsHandler) NULL)
3481 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003482 assert(id < (int) cache_info->number_threads);
3483 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003484}
3485
3486/*
3487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3488% %
3489% %
3490% %
3491% G e t V i r t u a l P i x e l s %
3492% %
3493% %
3494% %
3495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3496%
3497% GetVirtualPixels() returns an immutable pixel region. If the
3498% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003499% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003500% copy of the pixels or it may point to the original pixels in memory.
3501% Performance is maximized if the selected region is part of one row, or one
3502% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003503% (without a copy) if the image is in memory, or in a memory-mapped file. The
3504% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003505%
3506% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003507% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3508% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3509% access the meta-content (of type void) corresponding to the the
3510% region.
cristy3ed852e2009-09-05 21:47:34 +00003511%
3512% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3513%
3514% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3515% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3516% GetCacheViewAuthenticPixels() instead.
3517%
3518% The format of the GetVirtualPixels() method is:
3519%
cristy4c08aed2011-07-01 19:47:50 +00003520% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003521% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003522% ExceptionInfo *exception)
3523%
3524% A description of each parameter follows:
3525%
3526% o image: the image.
3527%
3528% o x,y,columns,rows: These values define the perimeter of a region of
3529% pixels.
3530%
3531% o exception: return any errors or warnings in this structure.
3532%
3533*/
cristy4c08aed2011-07-01 19:47:50 +00003534MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003535 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3536 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003537{
3538 CacheInfo
3539 *cache_info;
3540
cristy2036f5c2010-09-19 21:18:17 +00003541 const int
3542 id = GetOpenMPThreadId();
3543
cristy4c08aed2011-07-01 19:47:50 +00003544 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003545 *p;
cristy4c08aed2011-07-01 19:47:50 +00003546
cristy3ed852e2009-09-05 21:47:34 +00003547 assert(image != (const Image *) NULL);
3548 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003549 assert(image->cache != (Cache) NULL);
3550 cache_info=(CacheInfo *) image->cache;
3551 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003552 if (cache_info->methods.get_virtual_pixel_handler !=
3553 (GetVirtualPixelHandler) NULL)
3554 return(cache_info->methods.get_virtual_pixel_handler(image,
3555 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003556 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003557 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003558 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003559 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003560}
3561
3562/*
3563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3564% %
3565% %
3566% %
3567+ 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 %
3568% %
3569% %
3570% %
3571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3572%
cristy4c08aed2011-07-01 19:47:50 +00003573% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3574% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003575%
3576% The format of the GetVirtualPixelsCache() method is:
3577%
cristy4c08aed2011-07-01 19:47:50 +00003578% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003579%
3580% A description of each parameter follows:
3581%
3582% o image: the image.
3583%
3584*/
cristy4c08aed2011-07-01 19:47:50 +00003585static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003586{
3587 CacheInfo
3588 *cache_info;
3589
cristy5c9e6f22010-09-17 17:31:01 +00003590 const int
3591 id = GetOpenMPThreadId();
3592
cristye7cc7cf2010-09-21 13:26:47 +00003593 assert(image != (const Image *) NULL);
3594 assert(image->signature == MagickSignature);
3595 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003596 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003597 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003598 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003599 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003600}
3601
3602/*
3603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604% %
3605% %
3606% %
3607+ G e t V i r t u a l P i x e l s N e x u s %
3608% %
3609% %
3610% %
3611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3612%
3613% GetVirtualPixelsNexus() returns the pixels associated with the specified
3614% cache nexus.
3615%
3616% The format of the GetVirtualPixelsNexus() method is:
3617%
cristy4c08aed2011-07-01 19:47:50 +00003618% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003619% NexusInfo *nexus_info)
3620%
3621% A description of each parameter follows:
3622%
3623% o cache: the pixel cache.
3624%
3625% o nexus_info: the cache nexus to return the colormap pixels.
3626%
3627*/
cristya6577ff2011-09-02 19:54:26 +00003628MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003629 NexusInfo *nexus_info)
3630{
3631 CacheInfo
3632 *cache_info;
3633
cristye7cc7cf2010-09-21 13:26:47 +00003634 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003635 cache_info=(CacheInfo *) cache;
3636 assert(cache_info->signature == MagickSignature);
3637 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003638 return((Quantum *) NULL);
3639 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003640}
3641
3642/*
3643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3644% %
3645% %
3646% %
cristy3ed852e2009-09-05 21:47:34 +00003647+ O p e n P i x e l C a c h e %
3648% %
3649% %
3650% %
3651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3652%
3653% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3654% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003655% metacontent, and memory mapping the cache if it is disk based. The cache
3656% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003657%
3658% The format of the OpenPixelCache() method is:
3659%
3660% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3661% ExceptionInfo *exception)
3662%
3663% A description of each parameter follows:
3664%
3665% o image: the image.
3666%
3667% o mode: ReadMode, WriteMode, or IOMode.
3668%
3669% o exception: return any errors or warnings in this structure.
3670%
3671*/
3672
cristyd43a46b2010-01-21 02:13:41 +00003673static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003674{
3675 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003676 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003677 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003678 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003679 {
3680 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003681 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003682 cache_info->length);
3683 }
3684}
3685
3686static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3687{
3688 CacheInfo
3689 *cache_info;
3690
3691 MagickOffsetType
3692 count,
3693 extent,
3694 offset;
3695
3696 cache_info=(CacheInfo *) image->cache;
3697 if (image->debug != MagickFalse)
3698 {
3699 char
3700 format[MaxTextExtent],
3701 message[MaxTextExtent];
3702
cristyb9080c92009-12-01 20:13:26 +00003703 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003704 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003705 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003706 cache_info->cache_filename,cache_info->file,format);
3707 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3708 }
3709 if (length != (MagickSizeType) ((MagickOffsetType) length))
3710 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003711 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003712 if (extent < 0)
3713 return(MagickFalse);
3714 if ((MagickSizeType) extent >= length)
3715 return(MagickTrue);
3716 offset=(MagickOffsetType) length-1;
3717 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3718 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3719}
3720
3721static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3722 ExceptionInfo *exception)
3723{
cristy3ed852e2009-09-05 21:47:34 +00003724 CacheInfo
3725 *cache_info,
3726 source_info;
3727
cristyf3a6a9d2010-11-07 21:02:56 +00003728 char
3729 format[MaxTextExtent],
3730 message[MaxTextExtent];
3731
cristy4c08aed2011-07-01 19:47:50 +00003732 MagickBooleanType
3733 status;
3734
cristy3ed852e2009-09-05 21:47:34 +00003735 MagickSizeType
3736 length,
3737 number_pixels;
3738
cristy3ed852e2009-09-05 21:47:34 +00003739 size_t
cristye076a6e2010-08-15 19:59:43 +00003740 columns,
cristy3ed852e2009-09-05 21:47:34 +00003741 packet_size;
3742
cristye7cc7cf2010-09-21 13:26:47 +00003743 assert(image != (const Image *) NULL);
3744 assert(image->signature == MagickSignature);
3745 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003746 if (image->debug != MagickFalse)
3747 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3748 if ((image->columns == 0) || (image->rows == 0))
3749 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3750 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003751 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003752 source_info=(*cache_info);
3753 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003754 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003755 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003756 cache_info->storage_class=image->storage_class;
3757 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003758 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003759 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003760 cache_info->rows=image->rows;
3761 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003762 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003763 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003764 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3765 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003766 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003767 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003768 if (image->ping != MagickFalse)
3769 {
cristy73724512010-04-12 14:43:14 +00003770 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003771 cache_info->pixels=(Quantum *) NULL;
3772 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003773 cache_info->length=0;
3774 return(MagickTrue);
3775 }
cristy3ed852e2009-09-05 21:47:34 +00003776 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003777 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003778 if (image->metacontent_extent != 0)
3779 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003780 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003781 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003782 if (cache_info->columns != columns)
3783 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3784 image->filename);
3785 cache_info->length=length;
3786 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003787 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003788 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003789 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3790 {
3791 status=AcquireMagickResource(MemoryResource,cache_info->length);
3792 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3793 (cache_info->type == MemoryCache))
3794 {
cristyd43a46b2010-01-21 02:13:41 +00003795 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003796 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003797 cache_info->pixels=source_info.pixels;
3798 else
3799 {
3800 /*
3801 Create memory pixel cache.
3802 */
cristy4c08aed2011-07-01 19:47:50 +00003803 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003804 if (image->debug != MagickFalse)
3805 {
cristy32cacff2011-12-31 03:36:27 +00003806 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003807 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003808 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3809 cache_info->filename,cache_info->mapped != MagickFalse ?
3810 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003811 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003812 format);
cristy3ed852e2009-09-05 21:47:34 +00003813 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3814 message);
3815 }
cristy3ed852e2009-09-05 21:47:34 +00003816 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003817 cache_info->metacontent=(void *) NULL;
3818 if (cache_info->metacontent_extent != 0)
3819 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003820 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003821 if ((source_info.storage_class != UndefinedClass) &&
3822 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003823 {
cristy4c08aed2011-07-01 19:47:50 +00003824 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003825 exception);
3826 RelinquishPixelCachePixels(&source_info);
3827 }
cristy4c08aed2011-07-01 19:47:50 +00003828 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003829 }
3830 }
3831 RelinquishMagickResource(MemoryResource,cache_info->length);
3832 }
3833 /*
3834 Create pixel cache on disk.
3835 */
3836 status=AcquireMagickResource(DiskResource,cache_info->length);
3837 if (status == MagickFalse)
3838 {
3839 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003840 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003841 return(MagickFalse);
3842 }
cristy413f1302012-01-01 17:48:27 +00003843 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3844 {
3845 (void) ClosePixelCacheOnDisk(cache_info);
3846 *cache_info->cache_filename='\0';
3847 }
cristy3ed852e2009-09-05 21:47:34 +00003848 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3849 {
3850 RelinquishMagickResource(DiskResource,cache_info->length);
3851 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3852 image->filename);
3853 return(MagickFalse);
3854 }
3855 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3856 cache_info->length);
3857 if (status == MagickFalse)
3858 {
3859 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3860 image->filename);
3861 return(MagickFalse);
3862 }
cristyed231572011-07-14 02:18:59 +00003863 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003864 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003865 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003866 cache_info->type=DiskCache;
3867 else
3868 {
3869 status=AcquireMagickResource(MapResource,cache_info->length);
3870 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3871 (cache_info->type != MemoryCache))
3872 cache_info->type=DiskCache;
3873 else
3874 {
cristy4c08aed2011-07-01 19:47:50 +00003875 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003876 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003877 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003878 {
cristy3ed852e2009-09-05 21:47:34 +00003879 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003880 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003881 }
3882 else
3883 {
3884 /*
3885 Create file-backed memory-mapped pixel cache.
3886 */
cristy4c08aed2011-07-01 19:47:50 +00003887 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003888 (void) ClosePixelCacheOnDisk(cache_info);
3889 cache_info->type=MapCache;
3890 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003891 cache_info->metacontent=(void *) NULL;
3892 if (cache_info->metacontent_extent != 0)
3893 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003894 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003895 if ((source_info.storage_class != UndefinedClass) &&
3896 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003897 {
3898 status=ClonePixelCachePixels(cache_info,&source_info,
3899 exception);
3900 RelinquishPixelCachePixels(&source_info);
3901 }
3902 if (image->debug != MagickFalse)
3903 {
cristy413f1302012-01-01 17:48:27 +00003904 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003905 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003906 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003907 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003908 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003909 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003910 format);
cristy3ed852e2009-09-05 21:47:34 +00003911 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3912 message);
3913 }
cristy4c08aed2011-07-01 19:47:50 +00003914 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003915 }
3916 }
3917 RelinquishMagickResource(MapResource,cache_info->length);
3918 }
cristy4c08aed2011-07-01 19:47:50 +00003919 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003920 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003921 {
3922 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3923 RelinquishPixelCachePixels(&source_info);
3924 }
3925 if (image->debug != MagickFalse)
3926 {
cristyb9080c92009-12-01 20:13:26 +00003927 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003928 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003929 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003930 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003931 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003932 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003933 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3934 }
cristy4c08aed2011-07-01 19:47:50 +00003935 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003936}
3937
3938/*
3939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3940% %
3941% %
3942% %
3943+ P e r s i s t P i x e l C a c h e %
3944% %
3945% %
3946% %
3947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3948%
3949% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3950% persistent pixel cache is one that resides on disk and is not destroyed
3951% when the program exits.
3952%
3953% The format of the PersistPixelCache() method is:
3954%
3955% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3956% const MagickBooleanType attach,MagickOffsetType *offset,
3957% ExceptionInfo *exception)
3958%
3959% A description of each parameter follows:
3960%
3961% o image: the image.
3962%
3963% o filename: the persistent pixel cache filename.
3964%
cristyf3a6a9d2010-11-07 21:02:56 +00003965% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003966%
cristy3ed852e2009-09-05 21:47:34 +00003967% o initialize: A value other than zero initializes the persistent pixel
3968% cache.
3969%
3970% o offset: the offset in the persistent cache to store pixels.
3971%
3972% o exception: return any errors or warnings in this structure.
3973%
3974*/
3975MagickExport MagickBooleanType PersistPixelCache(Image *image,
3976 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3977 ExceptionInfo *exception)
3978{
3979 CacheInfo
3980 *cache_info,
3981 *clone_info;
3982
3983 Image
3984 clone_image;
3985
cristy3ed852e2009-09-05 21:47:34 +00003986 MagickBooleanType
3987 status;
3988
cristye076a6e2010-08-15 19:59:43 +00003989 ssize_t
3990 page_size;
3991
cristy3ed852e2009-09-05 21:47:34 +00003992 assert(image != (Image *) NULL);
3993 assert(image->signature == MagickSignature);
3994 if (image->debug != MagickFalse)
3995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3996 assert(image->cache != (void *) NULL);
3997 assert(filename != (const char *) NULL);
3998 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00003999 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004000 cache_info=(CacheInfo *) image->cache;
4001 assert(cache_info->signature == MagickSignature);
4002 if (attach != MagickFalse)
4003 {
4004 /*
cristy01b7eb02009-09-10 23:10:14 +00004005 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004006 */
4007 if (image->debug != MagickFalse)
4008 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004009 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004010 (void) CopyMagickString(cache_info->cache_filename,filename,
4011 MaxTextExtent);
4012 cache_info->type=DiskCache;
4013 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004014 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004015 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004016 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004017 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004018 }
cristy01b7eb02009-09-10 23:10:14 +00004019 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4020 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004021 {
cristyf84a1932010-01-03 18:00:18 +00004022 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004023 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004024 (cache_info->reference_count == 1))
4025 {
4026 int
4027 status;
4028
4029 /*
cristy01b7eb02009-09-10 23:10:14 +00004030 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004031 */
cristy320684d2011-09-23 14:55:47 +00004032 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004033 if (status == 0)
4034 {
4035 (void) CopyMagickString(cache_info->cache_filename,filename,
4036 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004037 *offset+=cache_info->length+page_size-(cache_info->length %
4038 page_size);
cristyf84a1932010-01-03 18:00:18 +00004039 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004040 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004041 if (image->debug != MagickFalse)
4042 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4043 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004044 return(MagickTrue);
4045 }
4046 }
cristyf84a1932010-01-03 18:00:18 +00004047 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004048 }
4049 /*
cristy01b7eb02009-09-10 23:10:14 +00004050 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004051 */
4052 clone_image=(*image);
4053 clone_info=(CacheInfo *) clone_image.cache;
4054 image->cache=ClonePixelCache(cache_info);
4055 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4056 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4057 cache_info->type=DiskCache;
4058 cache_info->offset=(*offset);
4059 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004060 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004061 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004062 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004063 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004064 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4065 return(status);
4066}
4067
4068/*
4069%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4070% %
4071% %
4072% %
cristyc11dace2012-01-24 16:39:46 +00004073+ 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 +00004074% %
4075% %
4076% %
4077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4078%
cristyc11dace2012-01-24 16:39:46 +00004079% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4080% defined by the region rectangle and returns a pointer to the region. This
4081% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004082% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4083% pixels are transferred, otherwise a NULL is returned.
4084%
cristyc11dace2012-01-24 16:39:46 +00004085% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004086%
cristyc11dace2012-01-24 16:39:46 +00004087% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004088% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004089% const MagickBooleanType clone,NexusInfo *nexus_info,
4090% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004091%
4092% A description of each parameter follows:
4093%
4094% o image: the image.
4095%
4096% o x,y,columns,rows: These values define the perimeter of a region of
4097% pixels.
4098%
4099% o nexus_info: the cache nexus to set.
4100%
cristy65dbf172011-10-06 17:32:04 +00004101% o clone: clone the pixel cache.
4102%
cristy3ed852e2009-09-05 21:47:34 +00004103% o exception: return any errors or warnings in this structure.
4104%
4105*/
cristyc11dace2012-01-24 16:39:46 +00004106MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4107 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004108 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004109{
4110 CacheInfo
4111 *cache_info;
4112
4113 MagickOffsetType
4114 offset;
4115
4116 MagickSizeType
4117 number_pixels;
4118
4119 RectangleInfo
4120 region;
4121
4122 /*
4123 Validate pixel cache geometry.
4124 */
cristye7cc7cf2010-09-21 13:26:47 +00004125 assert(image != (const Image *) NULL);
4126 assert(image->signature == MagickSignature);
4127 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004128 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004129 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004130 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004131 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004132 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4133 {
4134 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004135 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004136 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004137 }
cristybb503372010-05-27 20:51:26 +00004138 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4139 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004140 {
4141 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004142 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004143 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004144 }
4145 offset=(MagickOffsetType) y*cache_info->columns+x;
4146 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004147 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004148 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4149 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4150 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004151 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004152 /*
4153 Return pixel cache.
4154 */
4155 region.x=x;
4156 region.y=y;
4157 region.width=columns;
4158 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004159 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004160}
4161
4162/*
4163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4164% %
4165% %
4166% %
4167+ 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 %
4168% %
4169% %
4170% %
4171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4172%
4173% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4174% defined by the region rectangle and returns a pointer to the region. This
4175% region is subsequently transferred from the pixel cache with
4176% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4177% pixels are transferred, otherwise a NULL is returned.
4178%
4179% The format of the QueueAuthenticPixelsCache() method is:
4180%
cristy4c08aed2011-07-01 19:47:50 +00004181% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004182% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004183% ExceptionInfo *exception)
4184%
4185% A description of each parameter follows:
4186%
4187% o image: the image.
4188%
4189% o x,y,columns,rows: These values define the perimeter of a region of
4190% pixels.
4191%
4192% o exception: return any errors or warnings in this structure.
4193%
4194*/
cristy4c08aed2011-07-01 19:47:50 +00004195static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004196 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004197 ExceptionInfo *exception)
4198{
4199 CacheInfo
4200 *cache_info;
4201
cristy5c9e6f22010-09-17 17:31:01 +00004202 const int
4203 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004204
cristy4c08aed2011-07-01 19:47:50 +00004205 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004206 *q;
cristy4c08aed2011-07-01 19:47:50 +00004207
cristye7cc7cf2010-09-21 13:26:47 +00004208 assert(image != (const Image *) NULL);
4209 assert(image->signature == MagickSignature);
4210 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004211 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004212 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004213 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004214 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004215 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004216 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004217}
4218
4219/*
4220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4221% %
4222% %
4223% %
4224% Q u e u e A u t h e n t i c P i x e l s %
4225% %
4226% %
4227% %
4228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4229%
4230% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004231% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004232% region is returned, otherwise NULL is returned. The returned pointer may
4233% point to a temporary working buffer for the pixels or it may point to the
4234% final location of the pixels in memory.
4235%
4236% Write-only access means that any existing pixel values corresponding to
4237% the region are ignored. This is useful if the initial image is being
4238% created from scratch, or if the existing pixel values are to be
4239% completely replaced without need to refer to their pre-existing values.
4240% The application is free to read and write the pixel buffer returned by
4241% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4242% initialize the pixel array values. Initializing pixel array values is the
4243% application's responsibility.
4244%
4245% Performance is maximized if the selected region is part of one row, or
4246% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004247% pixels in-place (without a copy) if the image is in memory, or in a
4248% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004249% by the user.
4250%
4251% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004252% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4253% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4254% obtain the meta-content (of type void) corresponding to the region.
4255% Once the Quantum (and/or Quantum) array has been updated, the
4256% changes must be saved back to the underlying image using
4257% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004258%
4259% The format of the QueueAuthenticPixels() method is:
4260%
cristy4c08aed2011-07-01 19:47:50 +00004261% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004262% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004263% ExceptionInfo *exception)
4264%
4265% A description of each parameter follows:
4266%
4267% o image: the image.
4268%
4269% o x,y,columns,rows: These values define the perimeter of a region of
4270% pixels.
4271%
4272% o exception: return any errors or warnings in this structure.
4273%
4274*/
cristy4c08aed2011-07-01 19:47:50 +00004275MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004276 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004277 ExceptionInfo *exception)
4278{
4279 CacheInfo
4280 *cache_info;
4281
cristy2036f5c2010-09-19 21:18:17 +00004282 const int
4283 id = GetOpenMPThreadId();
4284
cristy4c08aed2011-07-01 19:47:50 +00004285 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004286 *q;
cristy4c08aed2011-07-01 19:47:50 +00004287
cristy3ed852e2009-09-05 21:47:34 +00004288 assert(image != (Image *) NULL);
4289 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004290 assert(image->cache != (Cache) NULL);
4291 cache_info=(CacheInfo *) image->cache;
4292 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004293 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004294 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004295 {
cristyc36c8822012-02-14 14:02:36 +00004296 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4297 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004298 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004299 }
cristy2036f5c2010-09-19 21:18:17 +00004300 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004301 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004302 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004303 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004304}
4305
4306/*
4307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4308% %
4309% %
4310% %
cristy4c08aed2011-07-01 19:47:50 +00004311+ 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 +00004312% %
4313% %
4314% %
4315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4316%
cristy4c08aed2011-07-01 19:47:50 +00004317% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004318% the pixel cache.
4319%
cristy4c08aed2011-07-01 19:47:50 +00004320% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004321%
cristy4c08aed2011-07-01 19:47:50 +00004322% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004323% NexusInfo *nexus_info,ExceptionInfo *exception)
4324%
4325% A description of each parameter follows:
4326%
4327% o cache_info: the pixel cache.
4328%
cristy4c08aed2011-07-01 19:47:50 +00004329% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004330%
4331% o exception: return any errors or warnings in this structure.
4332%
4333*/
cristy4c08aed2011-07-01 19:47:50 +00004334static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004335 NexusInfo *nexus_info,ExceptionInfo *exception)
4336{
4337 MagickOffsetType
4338 count,
4339 offset;
4340
4341 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004342 extent,
4343 length;
cristy3ed852e2009-09-05 21:47:34 +00004344
cristybb503372010-05-27 20:51:26 +00004345 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004346 y;
4347
cristy4c08aed2011-07-01 19:47:50 +00004348 register unsigned char
4349 *restrict q;
4350
cristybb503372010-05-27 20:51:26 +00004351 size_t
cristy3ed852e2009-09-05 21:47:34 +00004352 rows;
4353
cristy4c08aed2011-07-01 19:47:50 +00004354 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004355 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004356 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004357 return(MagickTrue);
4358 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4359 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004360 length=(MagickSizeType) nexus_info->region.width*
4361 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004362 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004363 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004364 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004365 switch (cache_info->type)
4366 {
4367 case MemoryCache:
4368 case MapCache:
4369 {
cristy4c08aed2011-07-01 19:47:50 +00004370 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004371 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004372
4373 /*
cristy4c08aed2011-07-01 19:47:50 +00004374 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004375 */
cristydd341db2010-03-04 19:06:38 +00004376 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004377 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004378 {
cristy48078b12010-09-23 17:11:01 +00004379 length=extent;
cristydd341db2010-03-04 19:06:38 +00004380 rows=1UL;
4381 }
cristy4c08aed2011-07-01 19:47:50 +00004382 p=(unsigned char *) cache_info->metacontent+offset*
4383 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004384 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004385 {
cristy8f036fe2010-09-18 02:02:00 +00004386 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004387 p+=cache_info->metacontent_extent*cache_info->columns;
4388 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004389 }
4390 break;
4391 }
4392 case DiskCache:
4393 {
4394 /*
cristy4c08aed2011-07-01 19:47:50 +00004395 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004396 */
4397 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4398 {
4399 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4400 cache_info->cache_filename);
4401 return(MagickFalse);
4402 }
cristydd341db2010-03-04 19:06:38 +00004403 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004404 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004405 {
cristy48078b12010-09-23 17:11:01 +00004406 length=extent;
cristydd341db2010-03-04 19:06:38 +00004407 rows=1UL;
4408 }
cristy48078b12010-09-23 17:11:01 +00004409 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004410 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004411 {
cristy48078b12010-09-23 17:11:01 +00004412 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004413 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004414 cache_info->metacontent_extent,length,(unsigned char *) q);
4415 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004416 break;
4417 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004418 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004419 }
cristyc11dace2012-01-24 16:39:46 +00004420 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4421 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004422 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004423 {
4424 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4425 cache_info->cache_filename);
4426 return(MagickFalse);
4427 }
4428 break;
4429 }
4430 default:
4431 break;
4432 }
4433 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004434 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004435 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004436 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004437 nexus_info->region.width,(double) nexus_info->region.height,(double)
4438 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004439 return(MagickTrue);
4440}
4441
4442/*
4443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4444% %
4445% %
4446% %
4447+ R e a d P i x e l C a c h e P i x e l s %
4448% %
4449% %
4450% %
4451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4452%
4453% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4454% cache.
4455%
4456% The format of the ReadPixelCachePixels() method is:
4457%
4458% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4459% NexusInfo *nexus_info,ExceptionInfo *exception)
4460%
4461% A description of each parameter follows:
4462%
4463% o cache_info: the pixel cache.
4464%
4465% o nexus_info: the cache nexus to read the pixels.
4466%
4467% o exception: return any errors or warnings in this structure.
4468%
4469*/
4470static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4471 NexusInfo *nexus_info,ExceptionInfo *exception)
4472{
4473 MagickOffsetType
4474 count,
4475 offset;
4476
4477 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004478 extent,
4479 length;
cristy3ed852e2009-09-05 21:47:34 +00004480
cristy4c08aed2011-07-01 19:47:50 +00004481 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004482 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004483
cristye076a6e2010-08-15 19:59:43 +00004484 register ssize_t
4485 y;
4486
cristybb503372010-05-27 20:51:26 +00004487 size_t
cristy3ed852e2009-09-05 21:47:34 +00004488 rows;
4489
cristy4c08aed2011-07-01 19:47:50 +00004490 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004491 return(MagickTrue);
4492 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4493 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004494 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004495 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004496 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004497 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004498 q=nexus_info->pixels;
4499 switch (cache_info->type)
4500 {
4501 case MemoryCache:
4502 case MapCache:
4503 {
cristy4c08aed2011-07-01 19:47:50 +00004504 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004505 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004506
4507 /*
4508 Read pixels from memory.
4509 */
cristydd341db2010-03-04 19:06:38 +00004510 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004511 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004512 {
cristy48078b12010-09-23 17:11:01 +00004513 length=extent;
cristydd341db2010-03-04 19:06:38 +00004514 rows=1UL;
4515 }
cristyed231572011-07-14 02:18:59 +00004516 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004517 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004518 {
cristy8f036fe2010-09-18 02:02:00 +00004519 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004520 p+=cache_info->number_channels*cache_info->columns;
4521 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004522 }
4523 break;
4524 }
4525 case DiskCache:
4526 {
4527 /*
4528 Read pixels from disk.
4529 */
4530 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4531 {
4532 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4533 cache_info->cache_filename);
4534 return(MagickFalse);
4535 }
cristydd341db2010-03-04 19:06:38 +00004536 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004537 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004538 {
cristy48078b12010-09-23 17:11:01 +00004539 length=extent;
cristydd341db2010-03-04 19:06:38 +00004540 rows=1UL;
4541 }
cristybb503372010-05-27 20:51:26 +00004542 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004543 {
4544 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004545 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004546 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004547 break;
4548 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004549 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004550 }
cristyc11dace2012-01-24 16:39:46 +00004551 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4552 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004553 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004554 {
4555 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4556 cache_info->cache_filename);
4557 return(MagickFalse);
4558 }
4559 break;
4560 }
4561 default:
4562 break;
4563 }
4564 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004565 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004566 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004567 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004568 nexus_info->region.width,(double) nexus_info->region.height,(double)
4569 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004570 return(MagickTrue);
4571}
4572
4573/*
4574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4575% %
4576% %
4577% %
4578+ R e f e r e n c e P i x e l C a c h e %
4579% %
4580% %
4581% %
4582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4583%
4584% ReferencePixelCache() increments the reference count associated with the
4585% pixel cache returning a pointer to the cache.
4586%
4587% The format of the ReferencePixelCache method is:
4588%
4589% Cache ReferencePixelCache(Cache cache_info)
4590%
4591% A description of each parameter follows:
4592%
4593% o cache_info: the pixel cache.
4594%
4595*/
cristya6577ff2011-09-02 19:54:26 +00004596MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004597{
4598 CacheInfo
4599 *cache_info;
4600
4601 assert(cache != (Cache *) NULL);
4602 cache_info=(CacheInfo *) cache;
4603 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004604 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004605 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004606 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004607 return(cache_info);
4608}
4609
4610/*
4611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4612% %
4613% %
4614% %
4615+ S e t P i x e l C a c h e M e t h o d s %
4616% %
4617% %
4618% %
4619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4620%
4621% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4622%
4623% The format of the SetPixelCacheMethods() method is:
4624%
4625% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4626%
4627% A description of each parameter follows:
4628%
4629% o cache: the pixel cache.
4630%
4631% o cache_methods: Specifies a pointer to a CacheMethods structure.
4632%
4633*/
cristya6577ff2011-09-02 19:54:26 +00004634MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004635{
4636 CacheInfo
4637 *cache_info;
4638
4639 GetOneAuthenticPixelFromHandler
4640 get_one_authentic_pixel_from_handler;
4641
4642 GetOneVirtualPixelFromHandler
4643 get_one_virtual_pixel_from_handler;
4644
4645 /*
4646 Set cache pixel methods.
4647 */
4648 assert(cache != (Cache) NULL);
4649 assert(cache_methods != (CacheMethods *) NULL);
4650 cache_info=(CacheInfo *) cache;
4651 assert(cache_info->signature == MagickSignature);
4652 if (cache_info->debug != MagickFalse)
4653 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4654 cache_info->filename);
4655 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4656 cache_info->methods.get_virtual_pixel_handler=
4657 cache_methods->get_virtual_pixel_handler;
4658 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4659 cache_info->methods.destroy_pixel_handler=
4660 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004661 if (cache_methods->get_virtual_metacontent_from_handler !=
4662 (GetVirtualMetacontentFromHandler) NULL)
4663 cache_info->methods.get_virtual_metacontent_from_handler=
4664 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004665 if (cache_methods->get_authentic_pixels_handler !=
4666 (GetAuthenticPixelsHandler) NULL)
4667 cache_info->methods.get_authentic_pixels_handler=
4668 cache_methods->get_authentic_pixels_handler;
4669 if (cache_methods->queue_authentic_pixels_handler !=
4670 (QueueAuthenticPixelsHandler) NULL)
4671 cache_info->methods.queue_authentic_pixels_handler=
4672 cache_methods->queue_authentic_pixels_handler;
4673 if (cache_methods->sync_authentic_pixels_handler !=
4674 (SyncAuthenticPixelsHandler) NULL)
4675 cache_info->methods.sync_authentic_pixels_handler=
4676 cache_methods->sync_authentic_pixels_handler;
4677 if (cache_methods->get_authentic_pixels_from_handler !=
4678 (GetAuthenticPixelsFromHandler) NULL)
4679 cache_info->methods.get_authentic_pixels_from_handler=
4680 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004681 if (cache_methods->get_authentic_metacontent_from_handler !=
4682 (GetAuthenticMetacontentFromHandler) NULL)
4683 cache_info->methods.get_authentic_metacontent_from_handler=
4684 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004685 get_one_virtual_pixel_from_handler=
4686 cache_info->methods.get_one_virtual_pixel_from_handler;
4687 if (get_one_virtual_pixel_from_handler !=
4688 (GetOneVirtualPixelFromHandler) NULL)
4689 cache_info->methods.get_one_virtual_pixel_from_handler=
4690 cache_methods->get_one_virtual_pixel_from_handler;
4691 get_one_authentic_pixel_from_handler=
4692 cache_methods->get_one_authentic_pixel_from_handler;
4693 if (get_one_authentic_pixel_from_handler !=
4694 (GetOneAuthenticPixelFromHandler) NULL)
4695 cache_info->methods.get_one_authentic_pixel_from_handler=
4696 cache_methods->get_one_authentic_pixel_from_handler;
4697}
4698
4699/*
4700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4701% %
4702% %
4703% %
4704+ S e t P i x e l C a c h e N e x u s P i x e l s %
4705% %
4706% %
4707% %
4708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4709%
4710% SetPixelCacheNexusPixels() defines the region of the cache for the
4711% specified cache nexus.
4712%
4713% The format of the SetPixelCacheNexusPixels() method is:
4714%
cristy265a2b22012-05-11 12:48:50 +00004715% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004716% const RectangleInfo *region,NexusInfo *nexus_info,
4717% ExceptionInfo *exception)
4718%
4719% A description of each parameter follows:
4720%
4721% o image: the image.
4722%
cristy265a2b22012-05-11 12:48:50 +00004723% o mode: ReadMode, WriteMode, or IOMode.
4724%
cristy3ed852e2009-09-05 21:47:34 +00004725% 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
cristyf1832792012-05-08 18:38:18 +00004734static inline MagickBooleanType AcquireCacheNexusPixels(
4735 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4736 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004737{
4738 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4739 return(MagickFalse);
4740 nexus_info->mapped=MagickFalse;
cristy64c3edf2012-04-13 18:50:13 +00004741 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00004742 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004743 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004744 {
4745 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004746 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004747 nexus_info->length);
4748 }
cristy4c08aed2011-07-01 19:47:50 +00004749 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004750 {
4751 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004752 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004753 cache_info->filename);
4754 return(MagickFalse);
4755 }
4756 return(MagickTrue);
4757}
4758
cristyadf82722012-05-11 17:34:16 +00004759static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4760 const MapMode mode)
4761{
cristyfc5845e2012-05-11 18:18:13 +00004762 if (mode == ReadMode)
4763 {
4764 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4765 return;
4766 }
4767 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004768}
4769
cristy265a2b22012-05-11 12:48:50 +00004770static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004771 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4772{
4773 CacheInfo
4774 *cache_info;
4775
4776 MagickBooleanType
4777 status;
4778
cristy3ed852e2009-09-05 21:47:34 +00004779 MagickSizeType
4780 length,
4781 number_pixels;
4782
cristy3ed852e2009-09-05 21:47:34 +00004783 cache_info=(CacheInfo *) image->cache;
4784 assert(cache_info->signature == MagickSignature);
4785 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004786 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004787 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004788 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004789 {
cristybb503372010-05-27 20:51:26 +00004790 ssize_t
cristybad067a2010-02-15 17:20:55 +00004791 x,
4792 y;
cristy3ed852e2009-09-05 21:47:34 +00004793
cristyeaedf062010-05-29 22:36:02 +00004794 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4795 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004796 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4797 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004798 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004799 ((nexus_info->region.width == cache_info->columns) ||
4800 ((nexus_info->region.width % cache_info->columns) == 0)))))
4801 {
4802 MagickOffsetType
4803 offset;
4804
4805 /*
4806 Pixels are accessed directly from memory.
4807 */
4808 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4809 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004810 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004811 offset;
4812 nexus_info->metacontent=(void *) NULL;
4813 if (cache_info->metacontent_extent != 0)
4814 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4815 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004816 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004817 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004818 }
4819 }
4820 /*
4821 Pixels are stored in a cache region until they are synced to the cache.
4822 */
4823 number_pixels=(MagickSizeType) nexus_info->region.width*
4824 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004825 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004826 if (cache_info->metacontent_extent != 0)
4827 length+=number_pixels*cache_info->metacontent_extent;
4828 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004829 {
4830 nexus_info->length=length;
4831 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4832 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004833 {
4834 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004835 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004836 }
cristy3ed852e2009-09-05 21:47:34 +00004837 }
4838 else
4839 if (nexus_info->length != length)
4840 {
4841 RelinquishCacheNexusPixels(nexus_info);
4842 nexus_info->length=length;
4843 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4844 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004845 {
4846 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004847 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004848 }
cristy3ed852e2009-09-05 21:47:34 +00004849 }
4850 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004851 nexus_info->metacontent=(void *) NULL;
4852 if (cache_info->metacontent_extent != 0)
4853 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004854 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004855 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004856 return(nexus_info->pixels);
4857}
4858
4859/*
4860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4861% %
4862% %
4863% %
4864% 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 %
4865% %
4866% %
4867% %
4868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4869%
4870% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4871% pixel cache and returns the previous setting. A virtual pixel is any pixel
4872% access that is outside the boundaries of the image cache.
4873%
4874% The format of the SetPixelCacheVirtualMethod() method is:
4875%
cristy387430f2012-02-07 13:09:46 +00004876% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4877% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004878%
4879% A description of each parameter follows:
4880%
4881% o image: the image.
4882%
4883% o virtual_pixel_method: choose the type of virtual pixel.
4884%
cristy387430f2012-02-07 13:09:46 +00004885% o exception: return any errors or warnings in this structure.
4886%
cristy3ed852e2009-09-05 21:47:34 +00004887*/
cristy3d4cb882012-02-07 19:11:26 +00004888
4889static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4890 ExceptionInfo *exception)
4891{
4892 CacheInfo
4893 *cache_info;
4894
cristyf2719112012-05-06 18:38:46 +00004895 CacheView
4896 *image_view;
4897
cristy3d4cb882012-02-07 19:11:26 +00004898 MagickBooleanType
4899 status;
4900
4901 ssize_t
4902 y;
4903
4904 assert(image != (Image *) NULL);
4905 assert(image->signature == MagickSignature);
4906 if (image->debug != MagickFalse)
4907 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4908 assert(image->cache != (Cache) NULL);
4909 cache_info=(CacheInfo *) image->cache;
4910 assert(cache_info->signature == MagickSignature);
4911 image->matte=MagickTrue;
4912 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004913 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004914#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00004915 #pragma omp parallel for schedule(static) shared(status) \
cristyddacdd12012-05-07 23:08:14 +00004916 dynamic_number_threads(image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004917#endif
4918 for (y=0; y < (ssize_t) image->rows; y++)
4919 {
cristy3d4cb882012-02-07 19:11:26 +00004920 register Quantum
4921 *restrict q;
4922
4923 register ssize_t
4924 x;
4925
4926 if (status == MagickFalse)
4927 continue;
cristy23d198a2012-03-13 13:48:08 +00004928 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004929 if (q == (Quantum *) NULL)
4930 {
4931 status=MagickFalse;
4932 continue;
4933 }
4934 for (x=0; x < (ssize_t) image->columns; x++)
4935 {
4936 SetPixelAlpha(image,alpha,q);
4937 q+=GetPixelChannels(image);
4938 }
cristy23d198a2012-03-13 13:48:08 +00004939 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004940 }
cristy23d198a2012-03-13 13:48:08 +00004941 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004942 return(status);
4943}
4944
cristy387430f2012-02-07 13:09:46 +00004945MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4946 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004947{
4948 CacheInfo
4949 *cache_info;
4950
4951 VirtualPixelMethod
4952 method;
4953
4954 assert(image != (Image *) NULL);
4955 assert(image->signature == MagickSignature);
4956 if (image->debug != MagickFalse)
4957 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4958 assert(image->cache != (Cache) NULL);
4959 cache_info=(CacheInfo *) image->cache;
4960 assert(cache_info->signature == MagickSignature);
4961 method=cache_info->virtual_pixel_method;
4962 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004963 switch (virtual_pixel_method)
4964 {
4965 case BackgroundVirtualPixelMethod:
4966 {
4967 if ((image->background_color.matte != MagickFalse) &&
4968 (image->matte == MagickFalse))
cristy3d4cb882012-02-07 19:11:26 +00004969 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004970 break;
4971 }
4972 case TransparentVirtualPixelMethod:
4973 {
4974 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00004975 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004976 break;
4977 }
4978 default:
4979 break;
4980 }
cristy3ed852e2009-09-05 21:47:34 +00004981 return(method);
4982}
4983
4984/*
4985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4986% %
4987% %
4988% %
4989+ 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 %
4990% %
4991% %
4992% %
4993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4994%
4995% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4996% in-memory or disk cache. The method returns MagickTrue if the pixel region
4997% is synced, otherwise MagickFalse.
4998%
4999% The format of the SyncAuthenticPixelCacheNexus() method is:
5000%
5001% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5002% NexusInfo *nexus_info,ExceptionInfo *exception)
5003%
5004% A description of each parameter follows:
5005%
5006% o image: the image.
5007%
5008% o nexus_info: the cache nexus to sync.
5009%
5010% o exception: return any errors or warnings in this structure.
5011%
5012*/
cristya6577ff2011-09-02 19:54:26 +00005013MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005014 NexusInfo *nexus_info,ExceptionInfo *exception)
5015{
5016 CacheInfo
5017 *cache_info;
5018
5019 MagickBooleanType
5020 status;
5021
5022 /*
5023 Transfer pixels to the cache.
5024 */
5025 assert(image != (Image *) NULL);
5026 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005027 if (image->cache == (Cache) NULL)
5028 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5029 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005030 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005031 if (cache_info->type == UndefinedCache)
5032 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005033 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005034 return(MagickTrue);
5035 assert(cache_info->signature == MagickSignature);
5036 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005037 if ((cache_info->metacontent_extent != 0) &&
5038 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005039 return(MagickFalse);
5040 return(status);
5041}
5042
5043/*
5044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5045% %
5046% %
5047% %
5048+ S y n c A u t h e n t i c P i x e l C a c h e %
5049% %
5050% %
5051% %
5052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5053%
5054% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5055% or disk cache. The method returns MagickTrue if the pixel region is synced,
5056% otherwise MagickFalse.
5057%
5058% The format of the SyncAuthenticPixelsCache() method is:
5059%
5060% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5061% ExceptionInfo *exception)
5062%
5063% A description of each parameter follows:
5064%
5065% o image: the image.
5066%
5067% o exception: return any errors or warnings in this structure.
5068%
5069*/
5070static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5071 ExceptionInfo *exception)
5072{
5073 CacheInfo
5074 *cache_info;
5075
cristy5c9e6f22010-09-17 17:31:01 +00005076 const int
5077 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005078
cristy4c08aed2011-07-01 19:47:50 +00005079 MagickBooleanType
5080 status;
5081
cristye7cc7cf2010-09-21 13:26:47 +00005082 assert(image != (Image *) NULL);
5083 assert(image->signature == MagickSignature);
5084 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005085 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005086 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005087 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005088 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5089 exception);
5090 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005091}
5092
5093/*
5094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5095% %
5096% %
5097% %
5098% S y n c A u t h e n t i c P i x e l s %
5099% %
5100% %
5101% %
5102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5103%
5104% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5105% The method returns MagickTrue if the pixel region is flushed, otherwise
5106% MagickFalse.
5107%
5108% The format of the SyncAuthenticPixels() method is:
5109%
5110% MagickBooleanType SyncAuthenticPixels(Image *image,
5111% ExceptionInfo *exception)
5112%
5113% A description of each parameter follows:
5114%
5115% o image: the image.
5116%
5117% o exception: return any errors or warnings in this structure.
5118%
5119*/
5120MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5121 ExceptionInfo *exception)
5122{
5123 CacheInfo
5124 *cache_info;
5125
cristy2036f5c2010-09-19 21:18:17 +00005126 const int
5127 id = GetOpenMPThreadId();
5128
cristy4c08aed2011-07-01 19:47:50 +00005129 MagickBooleanType
5130 status;
5131
cristy3ed852e2009-09-05 21:47:34 +00005132 assert(image != (Image *) NULL);
5133 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005134 assert(image->cache != (Cache) NULL);
5135 cache_info=(CacheInfo *) image->cache;
5136 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005137 if (cache_info->methods.sync_authentic_pixels_handler !=
5138 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005139 {
5140 status=cache_info->methods.sync_authentic_pixels_handler(image,
5141 exception);
5142 return(status);
5143 }
cristy2036f5c2010-09-19 21:18:17 +00005144 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005145 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5146 exception);
5147 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005148}
5149
5150/*
5151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152% %
5153% %
5154% %
cristyd1dd6e42011-09-04 01:46:08 +00005155+ 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 +00005156% %
5157% %
5158% %
5159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5160%
5161% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5162% The method returns MagickTrue if the pixel region is flushed, otherwise
5163% MagickFalse.
5164%
5165% The format of the SyncImagePixelCache() method is:
5166%
5167% MagickBooleanType SyncImagePixelCache(Image *image,
5168% ExceptionInfo *exception)
5169%
5170% A description of each parameter follows:
5171%
5172% o image: the image.
5173%
5174% o exception: return any errors or warnings in this structure.
5175%
5176*/
cristyd1dd6e42011-09-04 01:46:08 +00005177MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005178 ExceptionInfo *exception)
5179{
5180 CacheInfo
5181 *cache_info;
5182
5183 assert(image != (Image *) NULL);
5184 assert(exception != (ExceptionInfo *) NULL);
5185 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5186 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5187}
5188
5189/*
5190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5191% %
5192% %
5193% %
cristy4c08aed2011-07-01 19:47:50 +00005194+ 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 +00005195% %
5196% %
5197% %
5198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5199%
cristy4c08aed2011-07-01 19:47:50 +00005200% WritePixelCacheMetacontent() writes the meta-content to the specified region
5201% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005202%
cristy4c08aed2011-07-01 19:47:50 +00005203% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005204%
cristy4c08aed2011-07-01 19:47:50 +00005205% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005206% NexusInfo *nexus_info,ExceptionInfo *exception)
5207%
5208% A description of each parameter follows:
5209%
5210% o cache_info: the pixel cache.
5211%
cristy4c08aed2011-07-01 19:47:50 +00005212% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005213%
5214% o exception: return any errors or warnings in this structure.
5215%
5216*/
cristy4c08aed2011-07-01 19:47:50 +00005217static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005218 NexusInfo *nexus_info,ExceptionInfo *exception)
5219{
5220 MagickOffsetType
5221 count,
5222 offset;
5223
5224 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005225 extent,
5226 length;
cristy3ed852e2009-09-05 21:47:34 +00005227
cristy4c08aed2011-07-01 19:47:50 +00005228 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005229 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005230
cristybb503372010-05-27 20:51:26 +00005231 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005232 y;
5233
cristybb503372010-05-27 20:51:26 +00005234 size_t
cristy3ed852e2009-09-05 21:47:34 +00005235 rows;
5236
cristy4c08aed2011-07-01 19:47:50 +00005237 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005238 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005239 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005240 return(MagickTrue);
5241 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5242 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005243 length=(MagickSizeType) nexus_info->region.width*
5244 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005245 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005246 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005247 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005248 switch (cache_info->type)
5249 {
5250 case MemoryCache:
5251 case MapCache:
5252 {
cristy4c08aed2011-07-01 19:47:50 +00005253 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005254 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005255
5256 /*
cristy4c08aed2011-07-01 19:47:50 +00005257 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005258 */
cristydd341db2010-03-04 19:06:38 +00005259 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005260 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005261 {
cristy48078b12010-09-23 17:11:01 +00005262 length=extent;
cristydd341db2010-03-04 19:06:38 +00005263 rows=1UL;
5264 }
cristy4c08aed2011-07-01 19:47:50 +00005265 q=(unsigned char *) cache_info->metacontent+offset*
5266 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005267 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005268 {
cristy8f036fe2010-09-18 02:02:00 +00005269 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005270 p+=nexus_info->region.width*cache_info->metacontent_extent;
5271 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005272 }
5273 break;
5274 }
5275 case DiskCache:
5276 {
5277 /*
cristy4c08aed2011-07-01 19:47:50 +00005278 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005279 */
5280 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5281 {
5282 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5283 cache_info->cache_filename);
5284 return(MagickFalse);
5285 }
cristydd341db2010-03-04 19:06:38 +00005286 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005287 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005288 {
cristy48078b12010-09-23 17:11:01 +00005289 length=extent;
cristydd341db2010-03-04 19:06:38 +00005290 rows=1UL;
5291 }
cristy48078b12010-09-23 17:11:01 +00005292 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005293 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005294 {
cristy48078b12010-09-23 17:11:01 +00005295 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005296 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005297 cache_info->metacontent_extent,length,(const unsigned char *) p);
5298 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005299 break;
cristy4c08aed2011-07-01 19:47:50 +00005300 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005301 offset+=cache_info->columns;
5302 }
cristyc11dace2012-01-24 16:39:46 +00005303 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5304 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005305 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005306 {
5307 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5308 cache_info->cache_filename);
5309 return(MagickFalse);
5310 }
5311 break;
5312 }
5313 default:
5314 break;
5315 }
5316 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005317 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005318 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005319 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005320 nexus_info->region.width,(double) nexus_info->region.height,(double)
5321 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005322 return(MagickTrue);
5323}
5324
5325/*
5326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5327% %
5328% %
5329% %
5330+ W r i t e C a c h e P i x e l s %
5331% %
5332% %
5333% %
5334%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5335%
5336% WritePixelCachePixels() writes image pixels to the specified region of the
5337% pixel cache.
5338%
5339% The format of the WritePixelCachePixels() method is:
5340%
5341% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5342% NexusInfo *nexus_info,ExceptionInfo *exception)
5343%
5344% A description of each parameter follows:
5345%
5346% o cache_info: the pixel cache.
5347%
5348% o nexus_info: the cache nexus to write the pixels.
5349%
5350% o exception: return any errors or warnings in this structure.
5351%
5352*/
5353static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5354 NexusInfo *nexus_info,ExceptionInfo *exception)
5355{
5356 MagickOffsetType
5357 count,
5358 offset;
5359
5360 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005361 extent,
5362 length;
cristy3ed852e2009-09-05 21:47:34 +00005363
cristy4c08aed2011-07-01 19:47:50 +00005364 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005365 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005366
cristybb503372010-05-27 20:51:26 +00005367 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005368 y;
5369
cristybb503372010-05-27 20:51:26 +00005370 size_t
cristy3ed852e2009-09-05 21:47:34 +00005371 rows;
5372
cristy4c08aed2011-07-01 19:47:50 +00005373 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005374 return(MagickTrue);
5375 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5376 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005377 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005378 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005379 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005380 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005381 p=nexus_info->pixels;
5382 switch (cache_info->type)
5383 {
5384 case MemoryCache:
5385 case MapCache:
5386 {
cristy4c08aed2011-07-01 19:47:50 +00005387 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005388 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005389
5390 /*
5391 Write pixels to memory.
5392 */
cristydd341db2010-03-04 19:06:38 +00005393 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005394 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005395 {
cristy48078b12010-09-23 17:11:01 +00005396 length=extent;
cristydd341db2010-03-04 19:06:38 +00005397 rows=1UL;
5398 }
cristyed231572011-07-14 02:18:59 +00005399 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005400 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005401 {
cristy8f036fe2010-09-18 02:02:00 +00005402 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005403 p+=nexus_info->region.width*cache_info->number_channels;
5404 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005405 }
5406 break;
5407 }
5408 case DiskCache:
5409 {
5410 /*
5411 Write pixels to disk.
5412 */
5413 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5414 {
5415 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5416 cache_info->cache_filename);
5417 return(MagickFalse);
5418 }
cristydd341db2010-03-04 19:06:38 +00005419 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005420 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005421 {
cristy48078b12010-09-23 17:11:01 +00005422 length=extent;
cristydd341db2010-03-04 19:06:38 +00005423 rows=1UL;
5424 }
cristybb503372010-05-27 20:51:26 +00005425 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005426 {
5427 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005428 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005429 p);
5430 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005431 break;
cristyed231572011-07-14 02:18:59 +00005432 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005433 offset+=cache_info->columns;
5434 }
cristyc11dace2012-01-24 16:39:46 +00005435 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5436 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005437 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005438 {
5439 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5440 cache_info->cache_filename);
5441 return(MagickFalse);
5442 }
5443 break;
5444 }
5445 default:
5446 break;
5447 }
5448 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005449 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005450 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005451 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005452 nexus_info->region.width,(double) nexus_info->region.height,(double)
5453 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005454 return(MagickTrue);
5455}