blob: 050d1880e9ee57c9ef990ba95053972715d15b9f [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% %
cristyce1fe792012-05-16 15:58:37 +00001980+ G e t I m a g e P i x e l C a c h e T y p e %
1981% %
1982% %
1983% %
1984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985%
1986% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1987% DiskCache, MemoryCache, MapCache, or PingCache.
1988%
1989% The format of the GetImagePixelCacheType() method is:
1990%
1991% const CacheType GetImagePixelCacheType(const Image *image)
1992%
1993% A description of each parameter follows:
1994%
1995% o image: the image.
1996%
1997*/
1998MagickExport const CacheType GetImagePixelCacheType(const Image *image)
1999{
2000 CacheInfo
2001 *cache_info;
2002
2003 assert(image != (Image *) NULL);
2004 assert(image->signature == MagickSignature);
2005 assert(image->cache != (Cache) NULL);
2006 cache_info=(CacheInfo *) image->cache;
2007 return(cache_info->type);
2008}
2009
2010/*
2011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2012% %
2013% %
2014% %
cristy3ed852e2009-09-05 21:47:34 +00002015% G e t O n e A u t h e n t i c P i x e l %
2016% %
2017% %
2018% %
2019%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2020%
2021% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2022% location. The image background color is returned if an error occurs.
2023%
2024% The format of the GetOneAuthenticPixel() method is:
2025%
cristybb503372010-05-27 20:51:26 +00002026% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002027% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002028%
2029% A description of each parameter follows:
2030%
2031% o image: the image.
2032%
2033% o x,y: These values define the location of the pixel to return.
2034%
2035% o pixel: return a pixel at the specified (x,y) location.
2036%
2037% o exception: return any errors or warnings in this structure.
2038%
2039*/
cristyacbbb7c2010-06-30 18:56:48 +00002040MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002041 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002042{
2043 CacheInfo
2044 *cache_info;
2045
cristy4c08aed2011-07-01 19:47:50 +00002046 register Quantum
2047 *q;
cristy2036f5c2010-09-19 21:18:17 +00002048
cristy2ed42f62011-10-02 19:49:57 +00002049 register ssize_t
2050 i;
2051
cristy3ed852e2009-09-05 21:47:34 +00002052 assert(image != (Image *) NULL);
2053 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002054 assert(image->cache != (Cache) NULL);
2055 cache_info=(CacheInfo *) image->cache;
2056 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002057 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002058 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2059 (GetOneAuthenticPixelFromHandler) NULL)
2060 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2061 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002062 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2063 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002064 {
cristy9e0719b2011-12-29 03:45:45 +00002065 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2066 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2067 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2068 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2069 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002070 return(MagickFalse);
2071 }
2072 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2073 {
2074 PixelChannel
2075 channel;
2076
cristye2a912b2011-12-05 20:02:07 +00002077 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002078 pixel[channel]=q[i];
2079 }
cristy2036f5c2010-09-19 21:18:17 +00002080 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002081}
2082
2083/*
2084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2085% %
2086% %
2087% %
2088+ 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 %
2089% %
2090% %
2091% %
2092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2093%
2094% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2095% location. The image background color is returned if an error occurs.
2096%
2097% The format of the GetOneAuthenticPixelFromCache() method is:
2098%
2099% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002100% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002101% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002102%
2103% A description of each parameter follows:
2104%
2105% o image: the image.
2106%
2107% o x,y: These values define the location of the pixel to return.
2108%
2109% o pixel: return a pixel at the specified (x,y) location.
2110%
2111% o exception: return any errors or warnings in this structure.
2112%
2113*/
2114static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002115 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002116{
cristy098f78c2010-09-23 17:28:44 +00002117 CacheInfo
2118 *cache_info;
2119
2120 const int
2121 id = GetOpenMPThreadId();
2122
cristy4c08aed2011-07-01 19:47:50 +00002123 register Quantum
2124 *q;
cristy3ed852e2009-09-05 21:47:34 +00002125
cristy2ed42f62011-10-02 19:49:57 +00002126 register ssize_t
2127 i;
2128
cristy0158a4b2010-09-20 13:59:45 +00002129 assert(image != (const Image *) NULL);
2130 assert(image->signature == MagickSignature);
2131 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002132 cache_info=(CacheInfo *) image->cache;
2133 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002134 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002135 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002136 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2137 exception);
2138 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002139 {
cristy9e0719b2011-12-29 03:45:45 +00002140 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2141 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2142 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2143 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2144 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002145 return(MagickFalse);
2146 }
2147 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2148 {
2149 PixelChannel
2150 channel;
2151
cristye2a912b2011-12-05 20:02:07 +00002152 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002153 pixel[channel]=q[i];
2154 }
cristy3ed852e2009-09-05 21:47:34 +00002155 return(MagickTrue);
2156}
2157
2158/*
2159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2160% %
2161% %
2162% %
cristy3ed852e2009-09-05 21:47:34 +00002163% G e t O n e V i r t u a l P i x e l %
2164% %
2165% %
2166% %
2167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2168%
2169% GetOneVirtualPixel() returns a single virtual pixel at the specified
2170% (x,y) location. The image background color is returned if an error occurs.
2171% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2172%
2173% The format of the GetOneVirtualPixel() method is:
2174%
cristybb503372010-05-27 20:51:26 +00002175% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002176% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002177%
2178% A description of each parameter follows:
2179%
2180% o image: the image.
2181%
2182% o x,y: These values define the location of the pixel to return.
2183%
2184% o pixel: return a pixel at the specified (x,y) location.
2185%
2186% o exception: return any errors or warnings in this structure.
2187%
2188*/
2189MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002190 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002191{
cristy3ed852e2009-09-05 21:47:34 +00002192 CacheInfo
2193 *cache_info;
2194
cristy0158a4b2010-09-20 13:59:45 +00002195 const int
2196 id = GetOpenMPThreadId();
2197
cristy4c08aed2011-07-01 19:47:50 +00002198 const Quantum
2199 *p;
cristy2036f5c2010-09-19 21:18:17 +00002200
cristy2ed42f62011-10-02 19:49:57 +00002201 register ssize_t
2202 i;
2203
cristy3ed852e2009-09-05 21:47:34 +00002204 assert(image != (const Image *) NULL);
2205 assert(image->signature == MagickSignature);
2206 assert(image->cache != (Cache) NULL);
2207 cache_info=(CacheInfo *) image->cache;
2208 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002209 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002210 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2211 (GetOneVirtualPixelFromHandler) NULL)
2212 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2213 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002214 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002215 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002216 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002217 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002218 {
cristy9e0719b2011-12-29 03:45:45 +00002219 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2220 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2221 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2222 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2223 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002224 return(MagickFalse);
2225 }
2226 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2227 {
2228 PixelChannel
2229 channel;
2230
cristye2a912b2011-12-05 20:02:07 +00002231 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002232 pixel[channel]=p[i];
2233 }
cristy2036f5c2010-09-19 21:18:17 +00002234 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002235}
2236
2237/*
2238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2239% %
2240% %
2241% %
2242+ 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 %
2243% %
2244% %
2245% %
2246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247%
2248% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2249% specified (x,y) location. The image background color is returned if an
2250% error occurs.
2251%
2252% The format of the GetOneVirtualPixelFromCache() method is:
2253%
2254% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002255% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002256% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002257%
2258% A description of each parameter follows:
2259%
2260% o image: the image.
2261%
2262% o virtual_pixel_method: the virtual pixel method.
2263%
2264% o x,y: These values define the location of the pixel to return.
2265%
2266% o pixel: return a pixel at the specified (x,y) location.
2267%
2268% o exception: return any errors or warnings in this structure.
2269%
2270*/
2271static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002272 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002273 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002274{
cristy0158a4b2010-09-20 13:59:45 +00002275 CacheInfo
2276 *cache_info;
2277
2278 const int
2279 id = GetOpenMPThreadId();
2280
cristy4c08aed2011-07-01 19:47:50 +00002281 const Quantum
2282 *p;
cristy3ed852e2009-09-05 21:47:34 +00002283
cristy2ed42f62011-10-02 19:49:57 +00002284 register ssize_t
2285 i;
2286
cristye7cc7cf2010-09-21 13:26:47 +00002287 assert(image != (const Image *) NULL);
2288 assert(image->signature == MagickSignature);
2289 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002290 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002291 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002292 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002293 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002294 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002295 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002296 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002297 {
cristy9e0719b2011-12-29 03:45:45 +00002298 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2299 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2300 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2301 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2302 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002303 return(MagickFalse);
2304 }
2305 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2306 {
2307 PixelChannel
2308 channel;
2309
cristye2a912b2011-12-05 20:02:07 +00002310 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002311 pixel[channel]=p[i];
2312 }
cristy3ed852e2009-09-05 21:47:34 +00002313 return(MagickTrue);
2314}
2315
2316/*
2317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2318% %
2319% %
2320% %
cristy3aa93752011-12-18 15:54:24 +00002321% G e t O n e V i r t u a l P i x e l I n f o %
2322% %
2323% %
2324% %
2325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2326%
2327% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2328% location. The image background color is returned if an error occurs. If
2329% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2330%
2331% The format of the GetOneVirtualPixelInfo() method is:
2332%
2333% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2334% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2335% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2336%
2337% A description of each parameter follows:
2338%
2339% o image: the image.
2340%
2341% o virtual_pixel_method: the virtual pixel method.
2342%
2343% o x,y: these values define the location of the pixel to return.
2344%
2345% o pixel: return a pixel at the specified (x,y) location.
2346%
2347% o exception: return any errors or warnings in this structure.
2348%
2349*/
2350MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2351 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2352 PixelInfo *pixel,ExceptionInfo *exception)
2353{
2354 CacheInfo
2355 *cache_info;
2356
2357 const int
2358 id = GetOpenMPThreadId();
2359
2360 register const Quantum
2361 *p;
2362
2363 assert(image != (const Image *) NULL);
2364 assert(image->signature == MagickSignature);
2365 assert(image->cache != (Cache) NULL);
2366 cache_info=(CacheInfo *) image->cache;
2367 assert(cache_info->signature == MagickSignature);
2368 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002369 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002370 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2371 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002372 if (p == (const Quantum *) NULL)
2373 return(MagickFalse);
2374 GetPixelInfoPixel(image,p,pixel);
2375 return(MagickTrue);
2376}
2377
2378/*
2379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380% %
2381% %
2382% %
cristy3ed852e2009-09-05 21:47:34 +00002383+ G e t P i x e l C a c h e C o l o r s p a c e %
2384% %
2385% %
2386% %
2387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388%
2389% GetPixelCacheColorspace() returns the class type of the pixel cache.
2390%
2391% The format of the GetPixelCacheColorspace() method is:
2392%
2393% Colorspace GetPixelCacheColorspace(Cache cache)
2394%
2395% A description of each parameter follows:
2396%
2397% o cache: the pixel cache.
2398%
2399*/
cristya6577ff2011-09-02 19:54:26 +00002400MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002401{
2402 CacheInfo
2403 *cache_info;
2404
2405 assert(cache != (Cache) NULL);
2406 cache_info=(CacheInfo *) cache;
2407 assert(cache_info->signature == MagickSignature);
2408 if (cache_info->debug != MagickFalse)
2409 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2410 cache_info->filename);
2411 return(cache_info->colorspace);
2412}
2413
2414/*
2415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2416% %
2417% %
2418% %
2419+ G e t P i x e l C a c h e M e t h o d s %
2420% %
2421% %
2422% %
2423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2424%
2425% GetPixelCacheMethods() initializes the CacheMethods structure.
2426%
2427% The format of the GetPixelCacheMethods() method is:
2428%
2429% void GetPixelCacheMethods(CacheMethods *cache_methods)
2430%
2431% A description of each parameter follows:
2432%
2433% o cache_methods: Specifies a pointer to a CacheMethods structure.
2434%
2435*/
cristya6577ff2011-09-02 19:54:26 +00002436MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002437{
2438 assert(cache_methods != (CacheMethods *) NULL);
2439 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2440 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2441 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002442 cache_methods->get_virtual_metacontent_from_handler=
2443 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002444 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2445 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002446 cache_methods->get_authentic_metacontent_from_handler=
2447 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002448 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2449 cache_methods->get_one_authentic_pixel_from_handler=
2450 GetOneAuthenticPixelFromCache;
2451 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2452 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2453 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2454}
2455
2456/*
2457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2458% %
2459% %
2460% %
2461+ G e t P i x e l C a c h e N e x u s E x t e n t %
2462% %
2463% %
2464% %
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466%
cristy4c08aed2011-07-01 19:47:50 +00002467% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2468% corresponding with the last call to SetPixelCacheNexusPixels() or
2469% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002470%
2471% The format of the GetPixelCacheNexusExtent() method is:
2472%
2473% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2474% NexusInfo *nexus_info)
2475%
2476% A description of each parameter follows:
2477%
2478% o nexus_info: the nexus info.
2479%
2480*/
cristya6577ff2011-09-02 19:54:26 +00002481MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002482 NexusInfo *nexus_info)
2483{
2484 CacheInfo
2485 *cache_info;
2486
2487 MagickSizeType
2488 extent;
2489
cristy9f027d12011-09-21 01:17:17 +00002490 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002491 cache_info=(CacheInfo *) cache;
2492 assert(cache_info->signature == MagickSignature);
2493 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2494 if (extent == 0)
2495 return((MagickSizeType) cache_info->columns*cache_info->rows);
2496 return(extent);
2497}
2498
2499/*
2500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501% %
2502% %
2503% %
cristy4c08aed2011-07-01 19:47:50 +00002504+ 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 +00002505% %
2506% %
2507% %
2508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2509%
cristy4c08aed2011-07-01 19:47:50 +00002510% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2511% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002512%
cristy4c08aed2011-07-01 19:47:50 +00002513% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002514%
cristy4c08aed2011-07-01 19:47:50 +00002515% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002516% NexusInfo *nexus_info)
2517%
2518% A description of each parameter follows:
2519%
2520% o cache: the pixel cache.
2521%
cristy4c08aed2011-07-01 19:47:50 +00002522% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002523%
2524*/
cristya6577ff2011-09-02 19:54:26 +00002525MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002526 NexusInfo *nexus_info)
2527{
2528 CacheInfo
2529 *cache_info;
2530
cristy9f027d12011-09-21 01:17:17 +00002531 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002532 cache_info=(CacheInfo *) cache;
2533 assert(cache_info->signature == MagickSignature);
2534 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002535 return((void *) NULL);
2536 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002537}
2538
2539/*
2540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2541% %
2542% %
2543% %
2544+ G e t P i x e l C a c h e N e x u s P i x e l s %
2545% %
2546% %
2547% %
2548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549%
2550% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2551% cache nexus.
2552%
2553% The format of the GetPixelCacheNexusPixels() method is:
2554%
cristy4c08aed2011-07-01 19:47:50 +00002555% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002556% NexusInfo *nexus_info)
2557%
2558% A description of each parameter follows:
2559%
2560% o cache: the pixel cache.
2561%
2562% o nexus_info: the cache nexus to return the pixels.
2563%
2564*/
cristya6577ff2011-09-02 19:54:26 +00002565MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002566 NexusInfo *nexus_info)
2567{
2568 CacheInfo
2569 *cache_info;
2570
cristy9f027d12011-09-21 01:17:17 +00002571 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002572 cache_info=(CacheInfo *) cache;
2573 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002574 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002575 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002576 return(nexus_info->pixels);
2577}
2578
2579/*
2580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2581% %
2582% %
2583% %
cristy056ba772010-01-02 23:33:54 +00002584+ G e t P i x e l C a c h e P i x e l s %
2585% %
2586% %
2587% %
2588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2589%
2590% GetPixelCachePixels() returns the pixels associated with the specified image.
2591%
2592% The format of the GetPixelCachePixels() method is:
2593%
cristyf84a1932010-01-03 18:00:18 +00002594% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2595% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002596%
2597% A description of each parameter follows:
2598%
2599% o image: the image.
2600%
2601% o length: the pixel cache length.
2602%
cristyf84a1932010-01-03 18:00:18 +00002603% o exception: return any errors or warnings in this structure.
2604%
cristy056ba772010-01-02 23:33:54 +00002605*/
cristyd1dd6e42011-09-04 01:46:08 +00002606MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002607 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002608{
2609 CacheInfo
2610 *cache_info;
2611
2612 assert(image != (const Image *) NULL);
2613 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002614 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002615 assert(length != (MagickSizeType *) NULL);
2616 assert(exception != (ExceptionInfo *) NULL);
2617 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002618 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002619 assert(cache_info->signature == MagickSignature);
2620 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002621 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002622 return((void *) NULL);
2623 *length=cache_info->length;
2624 return((void *) cache_info->pixels);
2625}
2626
2627/*
2628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2629% %
2630% %
2631% %
cristyb32b90a2009-09-07 21:45:48 +00002632+ 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 +00002633% %
2634% %
2635% %
2636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2637%
2638% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2639%
2640% The format of the GetPixelCacheStorageClass() method is:
2641%
2642% ClassType GetPixelCacheStorageClass(Cache cache)
2643%
2644% A description of each parameter follows:
2645%
2646% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2647%
2648% o cache: the pixel cache.
2649%
2650*/
cristya6577ff2011-09-02 19:54:26 +00002651MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002652{
2653 CacheInfo
2654 *cache_info;
2655
2656 assert(cache != (Cache) NULL);
2657 cache_info=(CacheInfo *) cache;
2658 assert(cache_info->signature == MagickSignature);
2659 if (cache_info->debug != MagickFalse)
2660 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2661 cache_info->filename);
2662 return(cache_info->storage_class);
2663}
2664
2665/*
2666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2667% %
2668% %
2669% %
cristyb32b90a2009-09-07 21:45:48 +00002670+ G e t P i x e l C a c h e T i l e S i z e %
2671% %
2672% %
2673% %
2674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675%
2676% GetPixelCacheTileSize() returns the pixel cache tile size.
2677%
2678% The format of the GetPixelCacheTileSize() method is:
2679%
cristybb503372010-05-27 20:51:26 +00002680% void GetPixelCacheTileSize(const Image *image,size_t *width,
2681% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002682%
2683% A description of each parameter follows:
2684%
2685% o image: the image.
2686%
2687% o width: the optimize cache tile width in pixels.
2688%
2689% o height: the optimize cache tile height in pixels.
2690%
2691*/
cristya6577ff2011-09-02 19:54:26 +00002692MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002693 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002694{
cristy4c08aed2011-07-01 19:47:50 +00002695 CacheInfo
2696 *cache_info;
2697
cristyb32b90a2009-09-07 21:45:48 +00002698 assert(image != (Image *) NULL);
2699 assert(image->signature == MagickSignature);
2700 if (image->debug != MagickFalse)
2701 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002702 cache_info=(CacheInfo *) image->cache;
2703 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002704 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002705 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002706 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002707 *height=(*width);
2708}
2709
2710/*
2711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2712% %
2713% %
2714% %
2715+ G e t P i x e l C a c h e T y p e %
2716% %
2717% %
2718% %
2719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2720%
2721% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2722%
2723% The format of the GetPixelCacheType() method is:
2724%
2725% CacheType GetPixelCacheType(const Image *image)
2726%
2727% A description of each parameter follows:
2728%
2729% o image: the image.
2730%
2731*/
cristya6577ff2011-09-02 19:54:26 +00002732MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002733{
2734 CacheInfo
2735 *cache_info;
2736
2737 assert(image != (Image *) NULL);
2738 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002739 assert(image->cache != (Cache) NULL);
2740 cache_info=(CacheInfo *) image->cache;
2741 assert(cache_info->signature == MagickSignature);
2742 return(cache_info->type);
2743}
2744
2745/*
2746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2747% %
2748% %
2749% %
cristy3ed852e2009-09-05 21:47:34 +00002750+ 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 %
2751% %
2752% %
2753% %
2754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2755%
2756% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2757% pixel cache. A virtual pixel is any pixel access that is outside the
2758% boundaries of the image cache.
2759%
2760% The format of the GetPixelCacheVirtualMethod() method is:
2761%
2762% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2763%
2764% A description of each parameter follows:
2765%
2766% o image: the image.
2767%
2768*/
cristyd1dd6e42011-09-04 01:46:08 +00002769MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002770{
2771 CacheInfo
2772 *cache_info;
2773
2774 assert(image != (Image *) NULL);
2775 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002776 assert(image->cache != (Cache) NULL);
2777 cache_info=(CacheInfo *) image->cache;
2778 assert(cache_info->signature == MagickSignature);
2779 return(cache_info->virtual_pixel_method);
2780}
2781
2782/*
2783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2784% %
2785% %
2786% %
cristy4c08aed2011-07-01 19:47:50 +00002787+ 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 +00002788% %
2789% %
2790% %
2791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2792%
cristy4c08aed2011-07-01 19:47:50 +00002793% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2794% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002795%
cristy4c08aed2011-07-01 19:47:50 +00002796% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002797%
cristy4c08aed2011-07-01 19:47:50 +00002798% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002799%
2800% A description of each parameter follows:
2801%
2802% o image: the image.
2803%
2804*/
cristy4c08aed2011-07-01 19:47:50 +00002805static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002806{
2807 CacheInfo
2808 *cache_info;
2809
cristy5c9e6f22010-09-17 17:31:01 +00002810 const int
2811 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002812
cristy4c08aed2011-07-01 19:47:50 +00002813 const void
2814 *metacontent;
2815
cristye7cc7cf2010-09-21 13:26:47 +00002816 assert(image != (const Image *) NULL);
2817 assert(image->signature == MagickSignature);
2818 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002819 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002820 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002821 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002822 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2823 cache_info->nexus_info[id]);
2824 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002825}
2826
2827/*
2828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2829% %
2830% %
2831% %
cristy4c08aed2011-07-01 19:47:50 +00002832+ G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00002833% %
2834% %
2835% %
2836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2837%
cristy4c08aed2011-07-01 19:47:50 +00002838% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2839% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002840%
cristy4c08aed2011-07-01 19:47:50 +00002841% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002842%
cristy4c08aed2011-07-01 19:47:50 +00002843% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002844% NexusInfo *nexus_info)
2845%
2846% A description of each parameter follows:
2847%
2848% o cache: the pixel cache.
2849%
cristy4c08aed2011-07-01 19:47:50 +00002850% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002851%
2852*/
cristya6577ff2011-09-02 19:54:26 +00002853MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002854 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002855{
2856 CacheInfo
2857 *cache_info;
2858
cristye7cc7cf2010-09-21 13:26:47 +00002859 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002860 cache_info=(CacheInfo *) cache;
2861 assert(cache_info->signature == MagickSignature);
2862 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002863 return((void *) NULL);
2864 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002865}
2866
2867/*
2868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2869% %
2870% %
2871% %
cristy4c08aed2011-07-01 19:47:50 +00002872% 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 +00002873% %
2874% %
2875% %
2876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2877%
cristy4c08aed2011-07-01 19:47:50 +00002878% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2879% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2880% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002881%
cristy4c08aed2011-07-01 19:47:50 +00002882% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002883%
cristy4c08aed2011-07-01 19:47:50 +00002884% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002885%
2886% A description of each parameter follows:
2887%
2888% o image: the image.
2889%
2890*/
cristy4c08aed2011-07-01 19:47:50 +00002891MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002892{
2893 CacheInfo
2894 *cache_info;
2895
cristy2036f5c2010-09-19 21:18:17 +00002896 const int
2897 id = GetOpenMPThreadId();
2898
cristy4c08aed2011-07-01 19:47:50 +00002899 const void
2900 *metacontent;
2901
cristy3ed852e2009-09-05 21:47:34 +00002902 assert(image != (const Image *) NULL);
2903 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002904 assert(image->cache != (Cache) NULL);
2905 cache_info=(CacheInfo *) image->cache;
2906 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002907 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002908 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002909 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002910 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002911 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2912 cache_info->nexus_info[id]);
2913 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002914}
2915
2916/*
2917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2918% %
2919% %
2920% %
2921+ 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 %
2922% %
2923% %
2924% %
2925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2926%
2927% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2928% pixel cache as defined by the geometry parameters. A pointer to the pixels
2929% is returned if the pixels are transferred, otherwise a NULL is returned.
2930%
2931% The format of the GetVirtualPixelsFromNexus() method is:
2932%
cristy4c08aed2011-07-01 19:47:50 +00002933% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002934% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002935% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2936% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002937%
2938% A description of each parameter follows:
2939%
2940% o image: the image.
2941%
2942% o virtual_pixel_method: the virtual pixel method.
2943%
2944% o x,y,columns,rows: These values define the perimeter of a region of
2945% pixels.
2946%
2947% o nexus_info: the cache nexus to acquire.
2948%
2949% o exception: return any errors or warnings in this structure.
2950%
2951*/
2952
cristybb503372010-05-27 20:51:26 +00002953static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002954 DitherMatrix[64] =
2955 {
2956 0, 48, 12, 60, 3, 51, 15, 63,
2957 32, 16, 44, 28, 35, 19, 47, 31,
2958 8, 56, 4, 52, 11, 59, 7, 55,
2959 40, 24, 36, 20, 43, 27, 39, 23,
2960 2, 50, 14, 62, 1, 49, 13, 61,
2961 34, 18, 46, 30, 33, 17, 45, 29,
2962 10, 58, 6, 54, 9, 57, 5, 53,
2963 42, 26, 38, 22, 41, 25, 37, 21
2964 };
2965
cristybb503372010-05-27 20:51:26 +00002966static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002967{
cristybb503372010-05-27 20:51:26 +00002968 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002969 index;
2970
2971 index=x+DitherMatrix[x & 0x07]-32L;
2972 if (index < 0L)
2973 return(0L);
cristybb503372010-05-27 20:51:26 +00002974 if (index >= (ssize_t) columns)
2975 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002976 return(index);
2977}
2978
cristybb503372010-05-27 20:51:26 +00002979static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002980{
cristybb503372010-05-27 20:51:26 +00002981 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002982 index;
2983
2984 index=y+DitherMatrix[y & 0x07]-32L;
2985 if (index < 0L)
2986 return(0L);
cristybb503372010-05-27 20:51:26 +00002987 if (index >= (ssize_t) rows)
2988 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002989 return(index);
2990}
2991
cristybb503372010-05-27 20:51:26 +00002992static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002993{
2994 if (x < 0L)
2995 return(0L);
cristybb503372010-05-27 20:51:26 +00002996 if (x >= (ssize_t) columns)
2997 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002998 return(x);
2999}
3000
cristybb503372010-05-27 20:51:26 +00003001static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003002{
3003 if (y < 0L)
3004 return(0L);
cristybb503372010-05-27 20:51:26 +00003005 if (y >= (ssize_t) rows)
3006 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003007 return(y);
3008}
3009
cristybb503372010-05-27 20:51:26 +00003010static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003011{
cristybb503372010-05-27 20:51:26 +00003012 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003013}
3014
cristybb503372010-05-27 20:51:26 +00003015static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003016{
cristybb503372010-05-27 20:51:26 +00003017 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003018}
3019
cristybb503372010-05-27 20:51:26 +00003020static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3021 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003022{
3023 MagickModulo
3024 modulo;
3025
cristy6162bb42011-07-18 11:34:09 +00003026 /*
3027 Compute the remainder of dividing offset by extent. It returns not only
3028 the quotient (tile the offset falls in) but also the positive remainer
3029 within that tile such that 0 <= remainder < extent. This method is
3030 essentially a ldiv() using a floored modulo division rather than the
3031 normal default truncated modulo division.
3032 */
cristybb503372010-05-27 20:51:26 +00003033 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003034 if (offset < 0L)
3035 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003036 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003037 return(modulo);
3038}
3039
cristya6577ff2011-09-02 19:54:26 +00003040MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003041 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3042 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003043 ExceptionInfo *exception)
3044{
3045 CacheInfo
3046 *cache_info;
3047
3048 MagickOffsetType
3049 offset;
3050
3051 MagickSizeType
3052 length,
3053 number_pixels;
3054
3055 NexusInfo
3056 **virtual_nexus;
3057
cristy4c08aed2011-07-01 19:47:50 +00003058 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003059 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003060 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003061
3062 RectangleInfo
3063 region;
3064
cristy4c08aed2011-07-01 19:47:50 +00003065 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003066 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003067
cristy4c08aed2011-07-01 19:47:50 +00003068 register const void
3069 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003070
cristy4c08aed2011-07-01 19:47:50 +00003071 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003072 *restrict q;
3073
cristybb503372010-05-27 20:51:26 +00003074 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003075 i,
3076 u;
cristy3ed852e2009-09-05 21:47:34 +00003077
cristy4c08aed2011-07-01 19:47:50 +00003078 register unsigned char
3079 *restrict s;
3080
cristy105ba3c2011-07-18 02:28:38 +00003081 ssize_t
3082 v;
3083
cristy4c08aed2011-07-01 19:47:50 +00003084 void
cristy105ba3c2011-07-18 02:28:38 +00003085 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003086
cristy3ed852e2009-09-05 21:47:34 +00003087 /*
3088 Acquire pixels.
3089 */
cristye7cc7cf2010-09-21 13:26:47 +00003090 assert(image != (const Image *) NULL);
3091 assert(image->signature == MagickSignature);
3092 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003093 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003094 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003095 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003096 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003097 region.x=x;
3098 region.y=y;
3099 region.width=columns;
3100 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003101 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003102 if (pixels == (Quantum *) NULL)
3103 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003104 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003105 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3106 nexus_info->region.x;
3107 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3108 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003109 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3110 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003111 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3112 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003113 {
3114 MagickBooleanType
3115 status;
3116
3117 /*
3118 Pixel request is inside cache extents.
3119 */
cristy4c08aed2011-07-01 19:47:50 +00003120 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003121 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003122 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3123 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003124 return((const Quantum *) NULL);
3125 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003126 {
cristy4c08aed2011-07-01 19:47:50 +00003127 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003128 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003129 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003130 }
cristyacd2ed22011-08-30 01:44:23 +00003131 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003132 }
3133 /*
3134 Pixel request is outside cache extents.
3135 */
cristy4c08aed2011-07-01 19:47:50 +00003136 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003137 virtual_nexus=AcquirePixelCacheNexus(1);
3138 if (virtual_nexus == (NexusInfo **) NULL)
3139 {
cristy4c08aed2011-07-01 19:47:50 +00003140 if (virtual_nexus != (NexusInfo **) NULL)
3141 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003142 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003143 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003144 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003145 }
cristy105ba3c2011-07-18 02:28:38 +00003146 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3147 sizeof(*virtual_pixel));
3148 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003149 switch (virtual_pixel_method)
3150 {
cristy4c08aed2011-07-01 19:47:50 +00003151 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003152 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003153 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003154 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003155 case MaskVirtualPixelMethod:
3156 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003157 case EdgeVirtualPixelMethod:
3158 case CheckerTileVirtualPixelMethod:
3159 case HorizontalTileVirtualPixelMethod:
3160 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003161 {
cristy4c08aed2011-07-01 19:47:50 +00003162 if (cache_info->metacontent_extent != 0)
3163 {
cristy6162bb42011-07-18 11:34:09 +00003164 /*
3165 Acquire a metacontent buffer.
3166 */
cristya64b85d2011-09-14 01:02:31 +00003167 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003168 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003169 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003170 {
cristy4c08aed2011-07-01 19:47:50 +00003171 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3172 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003173 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003174 return((const Quantum *) NULL);
3175 }
cristy105ba3c2011-07-18 02:28:38 +00003176 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003177 cache_info->metacontent_extent);
3178 }
3179 switch (virtual_pixel_method)
3180 {
3181 case BlackVirtualPixelMethod:
3182 {
cristy30301712011-07-18 15:06:51 +00003183 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3184 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003185 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3186 break;
3187 }
3188 case GrayVirtualPixelMethod:
3189 {
cristy30301712011-07-18 15:06:51 +00003190 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003191 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3192 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003193 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3194 break;
3195 }
3196 case TransparentVirtualPixelMethod:
3197 {
cristy30301712011-07-18 15:06:51 +00003198 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3199 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003200 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3201 break;
3202 }
3203 case MaskVirtualPixelMethod:
3204 case WhiteVirtualPixelMethod:
3205 {
cristy30301712011-07-18 15:06:51 +00003206 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3207 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003208 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3209 break;
3210 }
3211 default:
3212 {
cristy9e0719b2011-12-29 03:45:45 +00003213 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3214 virtual_pixel);
3215 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3216 virtual_pixel);
3217 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3218 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003219 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3220 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003221 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3222 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003223 break;
3224 }
3225 }
cristy3ed852e2009-09-05 21:47:34 +00003226 break;
3227 }
3228 default:
cristy3ed852e2009-09-05 21:47:34 +00003229 break;
cristy3ed852e2009-09-05 21:47:34 +00003230 }
cristybb503372010-05-27 20:51:26 +00003231 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003232 {
cristybb503372010-05-27 20:51:26 +00003233 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003234 {
3235 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003236 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003237 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3238 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003239 {
3240 MagickModulo
3241 x_modulo,
3242 y_modulo;
3243
3244 /*
3245 Transfer a single pixel.
3246 */
3247 length=(MagickSizeType) 1;
3248 switch (virtual_pixel_method)
3249 {
cristy3ed852e2009-09-05 21:47:34 +00003250 default:
3251 {
3252 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003253 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003254 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003255 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003256 break;
3257 }
3258 case RandomVirtualPixelMethod:
3259 {
3260 if (cache_info->random_info == (RandomInfo *) NULL)
3261 cache_info->random_info=AcquireRandomInfo();
3262 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003263 RandomX(cache_info->random_info,cache_info->columns),
3264 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003265 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003266 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003267 break;
3268 }
3269 case DitherVirtualPixelMethod:
3270 {
3271 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003272 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003273 1UL,1UL,*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 TileVirtualPixelMethod:
3278 {
3279 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3280 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3281 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003282 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003283 exception);
cristy4c08aed2011-07-01 19:47:50 +00003284 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003285 break;
3286 }
3287 case MirrorVirtualPixelMethod:
3288 {
3289 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3290 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003291 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003292 x_modulo.remainder-1L;
3293 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3294 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003295 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003296 y_modulo.remainder-1L;
3297 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003298 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003299 exception);
cristy4c08aed2011-07-01 19:47:50 +00003300 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003301 break;
3302 }
3303 case HorizontalTileEdgeVirtualPixelMethod:
3304 {
3305 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3306 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003307 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003308 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003309 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003310 break;
3311 }
3312 case VerticalTileEdgeVirtualPixelMethod:
3313 {
3314 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3315 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003316 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003317 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003318 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3319 break;
3320 }
3321 case BackgroundVirtualPixelMethod:
3322 case BlackVirtualPixelMethod:
3323 case GrayVirtualPixelMethod:
3324 case TransparentVirtualPixelMethod:
3325 case MaskVirtualPixelMethod:
3326 case WhiteVirtualPixelMethod:
3327 {
3328 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003329 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003330 break;
3331 }
3332 case EdgeVirtualPixelMethod:
3333 case CheckerTileVirtualPixelMethod:
3334 {
3335 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3336 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3337 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3338 {
3339 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003340 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003341 break;
3342 }
3343 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3344 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3345 exception);
3346 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3347 break;
3348 }
3349 case HorizontalTileVirtualPixelMethod:
3350 {
3351 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3352 {
3353 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003354 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003355 break;
3356 }
3357 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3358 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3359 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3360 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3361 exception);
3362 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3363 break;
3364 }
3365 case VerticalTileVirtualPixelMethod:
3366 {
3367 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3368 {
3369 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003370 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003371 break;
3372 }
3373 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3374 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3375 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3376 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3377 exception);
3378 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003379 break;
3380 }
3381 }
cristy4c08aed2011-07-01 19:47:50 +00003382 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003383 break;
cristyed231572011-07-14 02:18:59 +00003384 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003385 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003386 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003387 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003388 {
3389 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3390 s+=cache_info->metacontent_extent;
3391 }
cristy3ed852e2009-09-05 21:47:34 +00003392 continue;
3393 }
3394 /*
3395 Transfer a run of pixels.
3396 */
cristy4c08aed2011-07-01 19:47:50 +00003397 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3398 length,1UL,*virtual_nexus,exception);
3399 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003400 break;
cristy4c08aed2011-07-01 19:47:50 +00003401 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003402 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3403 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003404 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003405 {
cristy4c08aed2011-07-01 19:47:50 +00003406 (void) memcpy(s,r,(size_t) length);
3407 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003408 }
3409 }
3410 }
cristy4c08aed2011-07-01 19:47:50 +00003411 /*
3412 Free resources.
3413 */
cristy105ba3c2011-07-18 02:28:38 +00003414 if (virtual_metacontent != (void *) NULL)
3415 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003416 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3417 return(pixels);
3418}
3419
3420/*
3421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3422% %
3423% %
3424% %
3425+ G e t V i r t u a l P i x e l C a c h e %
3426% %
3427% %
3428% %
3429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3430%
3431% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3432% cache as defined by the geometry parameters. A pointer to the pixels
3433% is returned if the pixels are transferred, otherwise a NULL is returned.
3434%
3435% The format of the GetVirtualPixelCache() method is:
3436%
cristy4c08aed2011-07-01 19:47:50 +00003437% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003438% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3439% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003440% ExceptionInfo *exception)
3441%
3442% A description of each parameter follows:
3443%
3444% o image: the image.
3445%
3446% o virtual_pixel_method: the virtual pixel method.
3447%
3448% o x,y,columns,rows: These values define the perimeter of a region of
3449% pixels.
3450%
3451% o exception: return any errors or warnings in this structure.
3452%
3453*/
cristy4c08aed2011-07-01 19:47:50 +00003454static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003455 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3456 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003457{
3458 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003459 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003460
cristy5c9e6f22010-09-17 17:31:01 +00003461 const int
3462 id = GetOpenMPThreadId();
3463
cristy4c08aed2011-07-01 19:47:50 +00003464 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003465 *p;
cristy4c08aed2011-07-01 19:47:50 +00003466
cristye7cc7cf2010-09-21 13:26:47 +00003467 assert(image != (const Image *) NULL);
3468 assert(image->signature == MagickSignature);
3469 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003470 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003471 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003472 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003473 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003474 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003475 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003476}
3477
3478/*
3479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3480% %
3481% %
3482% %
3483% G e t V i r t u a l P i x e l Q u e u e %
3484% %
3485% %
3486% %
3487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3488%
cristy4c08aed2011-07-01 19:47:50 +00003489% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3490% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003491%
3492% The format of the GetVirtualPixelQueue() method is:
3493%
cristy4c08aed2011-07-01 19:47:50 +00003494% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003495%
3496% A description of each parameter follows:
3497%
3498% o image: the image.
3499%
3500*/
cristy4c08aed2011-07-01 19:47:50 +00003501MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003502{
3503 CacheInfo
3504 *cache_info;
3505
cristy2036f5c2010-09-19 21:18:17 +00003506 const int
3507 id = GetOpenMPThreadId();
3508
cristy3ed852e2009-09-05 21:47:34 +00003509 assert(image != (const Image *) NULL);
3510 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003511 assert(image->cache != (Cache) NULL);
3512 cache_info=(CacheInfo *) image->cache;
3513 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003514 if (cache_info->methods.get_virtual_pixels_handler !=
3515 (GetVirtualPixelsHandler) NULL)
3516 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003517 assert(id < (int) cache_info->number_threads);
3518 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003519}
3520
3521/*
3522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3523% %
3524% %
3525% %
3526% G e t V i r t u a l P i x e l s %
3527% %
3528% %
3529% %
3530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3531%
3532% GetVirtualPixels() returns an immutable pixel region. If the
3533% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003534% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003535% copy of the pixels or it may point to the original pixels in memory.
3536% Performance is maximized if the selected region is part of one row, or one
3537% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003538% (without a copy) if the image is in memory, or in a memory-mapped file. The
3539% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003540%
3541% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003542% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3543% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3544% access the meta-content (of type void) corresponding to the the
3545% region.
cristy3ed852e2009-09-05 21:47:34 +00003546%
3547% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3548%
3549% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3550% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3551% GetCacheViewAuthenticPixels() instead.
3552%
3553% The format of the GetVirtualPixels() method is:
3554%
cristy4c08aed2011-07-01 19:47:50 +00003555% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003556% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003557% ExceptionInfo *exception)
3558%
3559% A description of each parameter follows:
3560%
3561% o image: the image.
3562%
3563% o x,y,columns,rows: These values define the perimeter of a region of
3564% pixels.
3565%
3566% o exception: return any errors or warnings in this structure.
3567%
3568*/
cristy4c08aed2011-07-01 19:47:50 +00003569MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003570 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3571 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003572{
3573 CacheInfo
3574 *cache_info;
3575
cristy2036f5c2010-09-19 21:18:17 +00003576 const int
3577 id = GetOpenMPThreadId();
3578
cristy4c08aed2011-07-01 19:47:50 +00003579 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003580 *p;
cristy4c08aed2011-07-01 19:47:50 +00003581
cristy3ed852e2009-09-05 21:47:34 +00003582 assert(image != (const Image *) NULL);
3583 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003584 assert(image->cache != (Cache) NULL);
3585 cache_info=(CacheInfo *) image->cache;
3586 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003587 if (cache_info->methods.get_virtual_pixel_handler !=
3588 (GetVirtualPixelHandler) NULL)
3589 return(cache_info->methods.get_virtual_pixel_handler(image,
3590 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003591 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003592 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003593 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003594 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003595}
3596
3597/*
3598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3599% %
3600% %
3601% %
3602+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3603% %
3604% %
3605% %
3606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3607%
cristy4c08aed2011-07-01 19:47:50 +00003608% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3609% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003610%
3611% The format of the GetVirtualPixelsCache() method is:
3612%
cristy4c08aed2011-07-01 19:47:50 +00003613% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003614%
3615% A description of each parameter follows:
3616%
3617% o image: the image.
3618%
3619*/
cristy4c08aed2011-07-01 19:47:50 +00003620static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003621{
3622 CacheInfo
3623 *cache_info;
3624
cristy5c9e6f22010-09-17 17:31:01 +00003625 const int
3626 id = GetOpenMPThreadId();
3627
cristye7cc7cf2010-09-21 13:26:47 +00003628 assert(image != (const Image *) NULL);
3629 assert(image->signature == MagickSignature);
3630 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003631 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003632 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003633 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003634 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003635}
3636
3637/*
3638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3639% %
3640% %
3641% %
3642+ G e t V i r t u a l P i x e l s N e x u s %
3643% %
3644% %
3645% %
3646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647%
3648% GetVirtualPixelsNexus() returns the pixels associated with the specified
3649% cache nexus.
3650%
3651% The format of the GetVirtualPixelsNexus() method is:
3652%
cristy4c08aed2011-07-01 19:47:50 +00003653% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003654% NexusInfo *nexus_info)
3655%
3656% A description of each parameter follows:
3657%
3658% o cache: the pixel cache.
3659%
3660% o nexus_info: the cache nexus to return the colormap pixels.
3661%
3662*/
cristya6577ff2011-09-02 19:54:26 +00003663MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003664 NexusInfo *nexus_info)
3665{
3666 CacheInfo
3667 *cache_info;
3668
cristye7cc7cf2010-09-21 13:26:47 +00003669 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003670 cache_info=(CacheInfo *) cache;
3671 assert(cache_info->signature == MagickSignature);
3672 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003673 return((Quantum *) NULL);
3674 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003675}
3676
3677/*
3678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3679% %
3680% %
3681% %
cristy3ed852e2009-09-05 21:47:34 +00003682+ O p e n P i x e l C a c h e %
3683% %
3684% %
3685% %
3686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3687%
3688% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3689% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003690% metacontent, and memory mapping the cache if it is disk based. The cache
3691% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003692%
3693% The format of the OpenPixelCache() method is:
3694%
3695% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3696% ExceptionInfo *exception)
3697%
3698% A description of each parameter follows:
3699%
3700% o image: the image.
3701%
3702% o mode: ReadMode, WriteMode, or IOMode.
3703%
3704% o exception: return any errors or warnings in this structure.
3705%
3706*/
3707
cristyd43a46b2010-01-21 02:13:41 +00003708static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003709{
3710 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003711 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003712 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003713 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003714 {
3715 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003716 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003717 cache_info->length);
3718 }
3719}
3720
3721static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3722{
3723 CacheInfo
3724 *cache_info;
3725
3726 MagickOffsetType
3727 count,
3728 extent,
3729 offset;
3730
3731 cache_info=(CacheInfo *) image->cache;
3732 if (image->debug != MagickFalse)
3733 {
3734 char
3735 format[MaxTextExtent],
3736 message[MaxTextExtent];
3737
cristyb9080c92009-12-01 20:13:26 +00003738 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003739 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003740 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003741 cache_info->cache_filename,cache_info->file,format);
3742 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3743 }
3744 if (length != (MagickSizeType) ((MagickOffsetType) length))
3745 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003746 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003747 if (extent < 0)
3748 return(MagickFalse);
3749 if ((MagickSizeType) extent >= length)
3750 return(MagickTrue);
3751 offset=(MagickOffsetType) length-1;
3752 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3753 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3754}
3755
3756static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3757 ExceptionInfo *exception)
3758{
cristy3ed852e2009-09-05 21:47:34 +00003759 CacheInfo
3760 *cache_info,
3761 source_info;
3762
cristyf3a6a9d2010-11-07 21:02:56 +00003763 char
3764 format[MaxTextExtent],
3765 message[MaxTextExtent];
3766
cristy4c08aed2011-07-01 19:47:50 +00003767 MagickBooleanType
3768 status;
3769
cristy3ed852e2009-09-05 21:47:34 +00003770 MagickSizeType
3771 length,
3772 number_pixels;
3773
cristy3ed852e2009-09-05 21:47:34 +00003774 size_t
cristye076a6e2010-08-15 19:59:43 +00003775 columns,
cristy3ed852e2009-09-05 21:47:34 +00003776 packet_size;
3777
cristye7cc7cf2010-09-21 13:26:47 +00003778 assert(image != (const Image *) NULL);
3779 assert(image->signature == MagickSignature);
3780 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003781 if (image->debug != MagickFalse)
3782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3783 if ((image->columns == 0) || (image->rows == 0))
3784 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3785 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003786 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003787 source_info=(*cache_info);
3788 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003789 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003790 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003791 cache_info->storage_class=image->storage_class;
3792 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003793 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003794 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003795 cache_info->rows=image->rows;
3796 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003797 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003798 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003799 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3800 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003801 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003802 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003803 if (image->ping != MagickFalse)
3804 {
cristy73724512010-04-12 14:43:14 +00003805 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003806 cache_info->pixels=(Quantum *) NULL;
3807 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003808 cache_info->length=0;
3809 return(MagickTrue);
3810 }
cristy3ed852e2009-09-05 21:47:34 +00003811 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003812 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003813 if (image->metacontent_extent != 0)
3814 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003815 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003816 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003817 if (cache_info->columns != columns)
3818 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3819 image->filename);
3820 cache_info->length=length;
3821 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003822 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003823 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003824 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3825 {
3826 status=AcquireMagickResource(MemoryResource,cache_info->length);
3827 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3828 (cache_info->type == MemoryCache))
3829 {
cristyd43a46b2010-01-21 02:13:41 +00003830 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003831 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003832 cache_info->pixels=source_info.pixels;
3833 else
3834 {
3835 /*
3836 Create memory pixel cache.
3837 */
cristy4c08aed2011-07-01 19:47:50 +00003838 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003839 if (image->debug != MagickFalse)
3840 {
cristy32cacff2011-12-31 03:36:27 +00003841 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003842 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003843 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3844 cache_info->filename,cache_info->mapped != MagickFalse ?
3845 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003846 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003847 format);
cristy3ed852e2009-09-05 21:47:34 +00003848 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3849 message);
3850 }
cristy3ed852e2009-09-05 21:47:34 +00003851 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003852 cache_info->metacontent=(void *) NULL;
3853 if (cache_info->metacontent_extent != 0)
3854 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003855 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003856 if ((source_info.storage_class != UndefinedClass) &&
3857 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003858 {
cristy4c08aed2011-07-01 19:47:50 +00003859 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003860 exception);
3861 RelinquishPixelCachePixels(&source_info);
3862 }
cristy4c08aed2011-07-01 19:47:50 +00003863 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003864 }
3865 }
3866 RelinquishMagickResource(MemoryResource,cache_info->length);
3867 }
3868 /*
3869 Create pixel cache on disk.
3870 */
3871 status=AcquireMagickResource(DiskResource,cache_info->length);
3872 if (status == MagickFalse)
3873 {
3874 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003875 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003876 return(MagickFalse);
3877 }
cristy413f1302012-01-01 17:48:27 +00003878 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3879 {
3880 (void) ClosePixelCacheOnDisk(cache_info);
3881 *cache_info->cache_filename='\0';
3882 }
cristy3ed852e2009-09-05 21:47:34 +00003883 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3884 {
3885 RelinquishMagickResource(DiskResource,cache_info->length);
3886 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3887 image->filename);
3888 return(MagickFalse);
3889 }
3890 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3891 cache_info->length);
3892 if (status == MagickFalse)
3893 {
3894 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3895 image->filename);
3896 return(MagickFalse);
3897 }
cristyed231572011-07-14 02:18:59 +00003898 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003899 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003900 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003901 cache_info->type=DiskCache;
3902 else
3903 {
3904 status=AcquireMagickResource(MapResource,cache_info->length);
3905 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3906 (cache_info->type != MemoryCache))
3907 cache_info->type=DiskCache;
3908 else
3909 {
cristy4c08aed2011-07-01 19:47:50 +00003910 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003911 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003912 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003913 {
cristy3ed852e2009-09-05 21:47:34 +00003914 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003915 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003916 }
3917 else
3918 {
3919 /*
3920 Create file-backed memory-mapped pixel cache.
3921 */
cristy4c08aed2011-07-01 19:47:50 +00003922 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003923 (void) ClosePixelCacheOnDisk(cache_info);
3924 cache_info->type=MapCache;
3925 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003926 cache_info->metacontent=(void *) NULL;
3927 if (cache_info->metacontent_extent != 0)
3928 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003929 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003930 if ((source_info.storage_class != UndefinedClass) &&
3931 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003932 {
3933 status=ClonePixelCachePixels(cache_info,&source_info,
3934 exception);
3935 RelinquishPixelCachePixels(&source_info);
3936 }
3937 if (image->debug != MagickFalse)
3938 {
cristy413f1302012-01-01 17:48:27 +00003939 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003940 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003941 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003942 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003943 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003944 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003945 format);
cristy3ed852e2009-09-05 21:47:34 +00003946 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3947 message);
3948 }
cristy4c08aed2011-07-01 19:47:50 +00003949 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003950 }
3951 }
3952 RelinquishMagickResource(MapResource,cache_info->length);
3953 }
cristy4c08aed2011-07-01 19:47:50 +00003954 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003955 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003956 {
3957 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3958 RelinquishPixelCachePixels(&source_info);
3959 }
3960 if (image->debug != MagickFalse)
3961 {
cristyb9080c92009-12-01 20:13:26 +00003962 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003963 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003964 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003965 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003966 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003967 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003968 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3969 }
cristy4c08aed2011-07-01 19:47:50 +00003970 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003971}
3972
3973/*
3974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3975% %
3976% %
3977% %
3978+ P e r s i s t P i x e l C a c h e %
3979% %
3980% %
3981% %
3982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3983%
3984% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3985% persistent pixel cache is one that resides on disk and is not destroyed
3986% when the program exits.
3987%
3988% The format of the PersistPixelCache() method is:
3989%
3990% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3991% const MagickBooleanType attach,MagickOffsetType *offset,
3992% ExceptionInfo *exception)
3993%
3994% A description of each parameter follows:
3995%
3996% o image: the image.
3997%
3998% o filename: the persistent pixel cache filename.
3999%
cristyf3a6a9d2010-11-07 21:02:56 +00004000% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004001%
cristy3ed852e2009-09-05 21:47:34 +00004002% o initialize: A value other than zero initializes the persistent pixel
4003% cache.
4004%
4005% o offset: the offset in the persistent cache to store pixels.
4006%
4007% o exception: return any errors or warnings in this structure.
4008%
4009*/
4010MagickExport MagickBooleanType PersistPixelCache(Image *image,
4011 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4012 ExceptionInfo *exception)
4013{
4014 CacheInfo
4015 *cache_info,
4016 *clone_info;
4017
4018 Image
4019 clone_image;
4020
cristy3ed852e2009-09-05 21:47:34 +00004021 MagickBooleanType
4022 status;
4023
cristye076a6e2010-08-15 19:59:43 +00004024 ssize_t
4025 page_size;
4026
cristy3ed852e2009-09-05 21:47:34 +00004027 assert(image != (Image *) NULL);
4028 assert(image->signature == MagickSignature);
4029 if (image->debug != MagickFalse)
4030 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4031 assert(image->cache != (void *) NULL);
4032 assert(filename != (const char *) NULL);
4033 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004034 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004035 cache_info=(CacheInfo *) image->cache;
4036 assert(cache_info->signature == MagickSignature);
4037 if (attach != MagickFalse)
4038 {
4039 /*
cristy01b7eb02009-09-10 23:10:14 +00004040 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004041 */
4042 if (image->debug != MagickFalse)
4043 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004044 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004045 (void) CopyMagickString(cache_info->cache_filename,filename,
4046 MaxTextExtent);
4047 cache_info->type=DiskCache;
4048 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004049 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004050 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004051 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004052 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004053 }
cristy01b7eb02009-09-10 23:10:14 +00004054 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4055 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004056 {
cristyf84a1932010-01-03 18:00:18 +00004057 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004058 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004059 (cache_info->reference_count == 1))
4060 {
4061 int
4062 status;
4063
4064 /*
cristy01b7eb02009-09-10 23:10:14 +00004065 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004066 */
cristy320684d2011-09-23 14:55:47 +00004067 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004068 if (status == 0)
4069 {
4070 (void) CopyMagickString(cache_info->cache_filename,filename,
4071 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004072 *offset+=cache_info->length+page_size-(cache_info->length %
4073 page_size);
cristyf84a1932010-01-03 18:00:18 +00004074 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004075 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004076 if (image->debug != MagickFalse)
4077 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4078 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004079 return(MagickTrue);
4080 }
4081 }
cristyf84a1932010-01-03 18:00:18 +00004082 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004083 }
4084 /*
cristy01b7eb02009-09-10 23:10:14 +00004085 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004086 */
4087 clone_image=(*image);
4088 clone_info=(CacheInfo *) clone_image.cache;
4089 image->cache=ClonePixelCache(cache_info);
4090 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4091 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4092 cache_info->type=DiskCache;
4093 cache_info->offset=(*offset);
4094 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004095 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004096 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004097 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004098 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004099 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4100 return(status);
4101}
4102
4103/*
4104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4105% %
4106% %
4107% %
cristyc11dace2012-01-24 16:39:46 +00004108+ 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 +00004109% %
4110% %
4111% %
4112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4113%
cristyc11dace2012-01-24 16:39:46 +00004114% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4115% defined by the region rectangle and returns a pointer to the region. This
4116% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004117% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4118% pixels are transferred, otherwise a NULL is returned.
4119%
cristyc11dace2012-01-24 16:39:46 +00004120% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004121%
cristyc11dace2012-01-24 16:39:46 +00004122% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004123% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004124% const MagickBooleanType clone,NexusInfo *nexus_info,
4125% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004126%
4127% A description of each parameter follows:
4128%
4129% o image: the image.
4130%
4131% o x,y,columns,rows: These values define the perimeter of a region of
4132% pixels.
4133%
4134% o nexus_info: the cache nexus to set.
4135%
cristy65dbf172011-10-06 17:32:04 +00004136% o clone: clone the pixel cache.
4137%
cristy3ed852e2009-09-05 21:47:34 +00004138% o exception: return any errors or warnings in this structure.
4139%
4140*/
cristyc11dace2012-01-24 16:39:46 +00004141MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4142 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004143 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004144{
4145 CacheInfo
4146 *cache_info;
4147
4148 MagickOffsetType
4149 offset;
4150
4151 MagickSizeType
4152 number_pixels;
4153
4154 RectangleInfo
4155 region;
4156
4157 /*
4158 Validate pixel cache geometry.
4159 */
cristye7cc7cf2010-09-21 13:26:47 +00004160 assert(image != (const Image *) NULL);
4161 assert(image->signature == MagickSignature);
4162 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004163 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004164 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004165 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004166 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004167 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4168 {
4169 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004170 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004171 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004172 }
cristybb503372010-05-27 20:51:26 +00004173 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4174 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004175 {
4176 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004177 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004178 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004179 }
4180 offset=(MagickOffsetType) y*cache_info->columns+x;
4181 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004182 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004183 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4184 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4185 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004186 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004187 /*
4188 Return pixel cache.
4189 */
4190 region.x=x;
4191 region.y=y;
4192 region.width=columns;
4193 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004194 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004195}
4196
4197/*
4198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4199% %
4200% %
4201% %
4202+ 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 %
4203% %
4204% %
4205% %
4206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4207%
4208% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4209% defined by the region rectangle and returns a pointer to the region. This
4210% region is subsequently transferred from the pixel cache with
4211% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4212% pixels are transferred, otherwise a NULL is returned.
4213%
4214% The format of the QueueAuthenticPixelsCache() method is:
4215%
cristy4c08aed2011-07-01 19:47:50 +00004216% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004217% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004218% ExceptionInfo *exception)
4219%
4220% A description of each parameter follows:
4221%
4222% o image: the image.
4223%
4224% o x,y,columns,rows: These values define the perimeter of a region of
4225% pixels.
4226%
4227% o exception: return any errors or warnings in this structure.
4228%
4229*/
cristy4c08aed2011-07-01 19:47:50 +00004230static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004231 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004232 ExceptionInfo *exception)
4233{
4234 CacheInfo
4235 *cache_info;
4236
cristy5c9e6f22010-09-17 17:31:01 +00004237 const int
4238 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004239
cristy4c08aed2011-07-01 19:47:50 +00004240 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004241 *q;
cristy4c08aed2011-07-01 19:47:50 +00004242
cristye7cc7cf2010-09-21 13:26:47 +00004243 assert(image != (const Image *) NULL);
4244 assert(image->signature == MagickSignature);
4245 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004246 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004247 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004248 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004249 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004250 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004251 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004252}
4253
4254/*
4255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4256% %
4257% %
4258% %
4259% Q u e u e A u t h e n t i c P i x e l s %
4260% %
4261% %
4262% %
4263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4264%
4265% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004266% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004267% region is returned, otherwise NULL is returned. The returned pointer may
4268% point to a temporary working buffer for the pixels or it may point to the
4269% final location of the pixels in memory.
4270%
4271% Write-only access means that any existing pixel values corresponding to
4272% the region are ignored. This is useful if the initial image is being
4273% created from scratch, or if the existing pixel values are to be
4274% completely replaced without need to refer to their pre-existing values.
4275% The application is free to read and write the pixel buffer returned by
4276% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4277% initialize the pixel array values. Initializing pixel array values is the
4278% application's responsibility.
4279%
4280% Performance is maximized if the selected region is part of one row, or
4281% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004282% pixels in-place (without a copy) if the image is in memory, or in a
4283% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004284% by the user.
4285%
4286% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004287% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4288% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4289% obtain the meta-content (of type void) corresponding to the region.
4290% Once the Quantum (and/or Quantum) array has been updated, the
4291% changes must be saved back to the underlying image using
4292% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004293%
4294% The format of the QueueAuthenticPixels() method is:
4295%
cristy4c08aed2011-07-01 19:47:50 +00004296% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004297% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004298% ExceptionInfo *exception)
4299%
4300% A description of each parameter follows:
4301%
4302% o image: the image.
4303%
4304% o x,y,columns,rows: These values define the perimeter of a region of
4305% pixels.
4306%
4307% o exception: return any errors or warnings in this structure.
4308%
4309*/
cristy4c08aed2011-07-01 19:47:50 +00004310MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004311 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004312 ExceptionInfo *exception)
4313{
4314 CacheInfo
4315 *cache_info;
4316
cristy2036f5c2010-09-19 21:18:17 +00004317 const int
4318 id = GetOpenMPThreadId();
4319
cristy4c08aed2011-07-01 19:47:50 +00004320 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004321 *q;
cristy4c08aed2011-07-01 19:47:50 +00004322
cristy3ed852e2009-09-05 21:47:34 +00004323 assert(image != (Image *) NULL);
4324 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004325 assert(image->cache != (Cache) NULL);
4326 cache_info=(CacheInfo *) image->cache;
4327 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004328 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004329 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004330 {
cristyc36c8822012-02-14 14:02:36 +00004331 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4332 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004333 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004334 }
cristy2036f5c2010-09-19 21:18:17 +00004335 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004336 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004337 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004338 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004339}
4340
4341/*
4342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4343% %
4344% %
4345% %
cristy4c08aed2011-07-01 19:47:50 +00004346+ 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 +00004347% %
4348% %
4349% %
4350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4351%
cristy4c08aed2011-07-01 19:47:50 +00004352% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004353% the pixel cache.
4354%
cristy4c08aed2011-07-01 19:47:50 +00004355% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004356%
cristy4c08aed2011-07-01 19:47:50 +00004357% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004358% NexusInfo *nexus_info,ExceptionInfo *exception)
4359%
4360% A description of each parameter follows:
4361%
4362% o cache_info: the pixel cache.
4363%
cristy4c08aed2011-07-01 19:47:50 +00004364% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004365%
4366% o exception: return any errors or warnings in this structure.
4367%
4368*/
cristy4c08aed2011-07-01 19:47:50 +00004369static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004370 NexusInfo *nexus_info,ExceptionInfo *exception)
4371{
4372 MagickOffsetType
4373 count,
4374 offset;
4375
4376 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004377 extent,
4378 length;
cristy3ed852e2009-09-05 21:47:34 +00004379
cristybb503372010-05-27 20:51:26 +00004380 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004381 y;
4382
cristy4c08aed2011-07-01 19:47:50 +00004383 register unsigned char
4384 *restrict q;
4385
cristybb503372010-05-27 20:51:26 +00004386 size_t
cristy3ed852e2009-09-05 21:47:34 +00004387 rows;
4388
cristy4c08aed2011-07-01 19:47:50 +00004389 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004390 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004391 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004392 return(MagickTrue);
4393 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4394 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004395 length=(MagickSizeType) nexus_info->region.width*
4396 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004397 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004398 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004399 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004400 switch (cache_info->type)
4401 {
4402 case MemoryCache:
4403 case MapCache:
4404 {
cristy4c08aed2011-07-01 19:47:50 +00004405 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004406 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004407
4408 /*
cristy4c08aed2011-07-01 19:47:50 +00004409 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004410 */
cristydd341db2010-03-04 19:06:38 +00004411 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004412 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004413 {
cristy48078b12010-09-23 17:11:01 +00004414 length=extent;
cristydd341db2010-03-04 19:06:38 +00004415 rows=1UL;
4416 }
cristy4c08aed2011-07-01 19:47:50 +00004417 p=(unsigned char *) cache_info->metacontent+offset*
4418 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004419 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004420 {
cristy8f036fe2010-09-18 02:02:00 +00004421 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004422 p+=cache_info->metacontent_extent*cache_info->columns;
4423 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004424 }
4425 break;
4426 }
4427 case DiskCache:
4428 {
4429 /*
cristy4c08aed2011-07-01 19:47:50 +00004430 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004431 */
4432 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4433 {
4434 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4435 cache_info->cache_filename);
4436 return(MagickFalse);
4437 }
cristydd341db2010-03-04 19:06:38 +00004438 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004439 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004440 {
cristy48078b12010-09-23 17:11:01 +00004441 length=extent;
cristydd341db2010-03-04 19:06:38 +00004442 rows=1UL;
4443 }
cristy48078b12010-09-23 17:11:01 +00004444 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004445 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004446 {
cristy48078b12010-09-23 17:11:01 +00004447 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004448 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004449 cache_info->metacontent_extent,length,(unsigned char *) q);
4450 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004451 break;
4452 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004453 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004454 }
cristyc11dace2012-01-24 16:39:46 +00004455 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4456 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004457 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004458 {
4459 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4460 cache_info->cache_filename);
4461 return(MagickFalse);
4462 }
4463 break;
4464 }
4465 default:
4466 break;
4467 }
4468 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004469 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004470 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004471 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004472 nexus_info->region.width,(double) nexus_info->region.height,(double)
4473 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004474 return(MagickTrue);
4475}
4476
4477/*
4478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4479% %
4480% %
4481% %
4482+ R e a d P i x e l C a c h e P i x e l s %
4483% %
4484% %
4485% %
4486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4487%
4488% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4489% cache.
4490%
4491% The format of the ReadPixelCachePixels() method is:
4492%
4493% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4494% NexusInfo *nexus_info,ExceptionInfo *exception)
4495%
4496% A description of each parameter follows:
4497%
4498% o cache_info: the pixel cache.
4499%
4500% o nexus_info: the cache nexus to read the pixels.
4501%
4502% o exception: return any errors or warnings in this structure.
4503%
4504*/
4505static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4506 NexusInfo *nexus_info,ExceptionInfo *exception)
4507{
4508 MagickOffsetType
4509 count,
4510 offset;
4511
4512 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004513 extent,
4514 length;
cristy3ed852e2009-09-05 21:47:34 +00004515
cristy4c08aed2011-07-01 19:47:50 +00004516 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004517 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004518
cristye076a6e2010-08-15 19:59:43 +00004519 register ssize_t
4520 y;
4521
cristybb503372010-05-27 20:51:26 +00004522 size_t
cristy3ed852e2009-09-05 21:47:34 +00004523 rows;
4524
cristy4c08aed2011-07-01 19:47:50 +00004525 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004526 return(MagickTrue);
4527 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4528 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004529 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004530 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004531 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004532 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004533 q=nexus_info->pixels;
4534 switch (cache_info->type)
4535 {
4536 case MemoryCache:
4537 case MapCache:
4538 {
cristy4c08aed2011-07-01 19:47:50 +00004539 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004540 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004541
4542 /*
4543 Read pixels from memory.
4544 */
cristydd341db2010-03-04 19:06:38 +00004545 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004546 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004547 {
cristy48078b12010-09-23 17:11:01 +00004548 length=extent;
cristydd341db2010-03-04 19:06:38 +00004549 rows=1UL;
4550 }
cristyed231572011-07-14 02:18:59 +00004551 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004552 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004553 {
cristy8f036fe2010-09-18 02:02:00 +00004554 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004555 p+=cache_info->number_channels*cache_info->columns;
4556 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004557 }
4558 break;
4559 }
4560 case DiskCache:
4561 {
4562 /*
4563 Read pixels from disk.
4564 */
4565 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4566 {
4567 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4568 cache_info->cache_filename);
4569 return(MagickFalse);
4570 }
cristydd341db2010-03-04 19:06:38 +00004571 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004572 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004573 {
cristy48078b12010-09-23 17:11:01 +00004574 length=extent;
cristydd341db2010-03-04 19:06:38 +00004575 rows=1UL;
4576 }
cristybb503372010-05-27 20:51:26 +00004577 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004578 {
4579 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004580 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004581 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004582 break;
4583 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004584 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004585 }
cristyc11dace2012-01-24 16:39:46 +00004586 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4587 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004588 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004589 {
4590 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4591 cache_info->cache_filename);
4592 return(MagickFalse);
4593 }
4594 break;
4595 }
4596 default:
4597 break;
4598 }
4599 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004600 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004601 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004602 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004603 nexus_info->region.width,(double) nexus_info->region.height,(double)
4604 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004605 return(MagickTrue);
4606}
4607
4608/*
4609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4610% %
4611% %
4612% %
4613+ R e f e r e n c e P i x e l C a c h e %
4614% %
4615% %
4616% %
4617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4618%
4619% ReferencePixelCache() increments the reference count associated with the
4620% pixel cache returning a pointer to the cache.
4621%
4622% The format of the ReferencePixelCache method is:
4623%
4624% Cache ReferencePixelCache(Cache cache_info)
4625%
4626% A description of each parameter follows:
4627%
4628% o cache_info: the pixel cache.
4629%
4630*/
cristya6577ff2011-09-02 19:54:26 +00004631MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004632{
4633 CacheInfo
4634 *cache_info;
4635
4636 assert(cache != (Cache *) NULL);
4637 cache_info=(CacheInfo *) cache;
4638 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004639 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004640 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004641 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004642 return(cache_info);
4643}
4644
4645/*
4646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4647% %
4648% %
4649% %
4650+ S e t P i x e l C a c h e M e t h o d s %
4651% %
4652% %
4653% %
4654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4655%
4656% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4657%
4658% The format of the SetPixelCacheMethods() method is:
4659%
4660% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4661%
4662% A description of each parameter follows:
4663%
4664% o cache: the pixel cache.
4665%
4666% o cache_methods: Specifies a pointer to a CacheMethods structure.
4667%
4668*/
cristya6577ff2011-09-02 19:54:26 +00004669MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004670{
4671 CacheInfo
4672 *cache_info;
4673
4674 GetOneAuthenticPixelFromHandler
4675 get_one_authentic_pixel_from_handler;
4676
4677 GetOneVirtualPixelFromHandler
4678 get_one_virtual_pixel_from_handler;
4679
4680 /*
4681 Set cache pixel methods.
4682 */
4683 assert(cache != (Cache) NULL);
4684 assert(cache_methods != (CacheMethods *) NULL);
4685 cache_info=(CacheInfo *) cache;
4686 assert(cache_info->signature == MagickSignature);
4687 if (cache_info->debug != MagickFalse)
4688 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4689 cache_info->filename);
4690 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4691 cache_info->methods.get_virtual_pixel_handler=
4692 cache_methods->get_virtual_pixel_handler;
4693 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4694 cache_info->methods.destroy_pixel_handler=
4695 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004696 if (cache_methods->get_virtual_metacontent_from_handler !=
4697 (GetVirtualMetacontentFromHandler) NULL)
4698 cache_info->methods.get_virtual_metacontent_from_handler=
4699 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004700 if (cache_methods->get_authentic_pixels_handler !=
4701 (GetAuthenticPixelsHandler) NULL)
4702 cache_info->methods.get_authentic_pixels_handler=
4703 cache_methods->get_authentic_pixels_handler;
4704 if (cache_methods->queue_authentic_pixels_handler !=
4705 (QueueAuthenticPixelsHandler) NULL)
4706 cache_info->methods.queue_authentic_pixels_handler=
4707 cache_methods->queue_authentic_pixels_handler;
4708 if (cache_methods->sync_authentic_pixels_handler !=
4709 (SyncAuthenticPixelsHandler) NULL)
4710 cache_info->methods.sync_authentic_pixels_handler=
4711 cache_methods->sync_authentic_pixels_handler;
4712 if (cache_methods->get_authentic_pixels_from_handler !=
4713 (GetAuthenticPixelsFromHandler) NULL)
4714 cache_info->methods.get_authentic_pixels_from_handler=
4715 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004716 if (cache_methods->get_authentic_metacontent_from_handler !=
4717 (GetAuthenticMetacontentFromHandler) NULL)
4718 cache_info->methods.get_authentic_metacontent_from_handler=
4719 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004720 get_one_virtual_pixel_from_handler=
4721 cache_info->methods.get_one_virtual_pixel_from_handler;
4722 if (get_one_virtual_pixel_from_handler !=
4723 (GetOneVirtualPixelFromHandler) NULL)
4724 cache_info->methods.get_one_virtual_pixel_from_handler=
4725 cache_methods->get_one_virtual_pixel_from_handler;
4726 get_one_authentic_pixel_from_handler=
4727 cache_methods->get_one_authentic_pixel_from_handler;
4728 if (get_one_authentic_pixel_from_handler !=
4729 (GetOneAuthenticPixelFromHandler) NULL)
4730 cache_info->methods.get_one_authentic_pixel_from_handler=
4731 cache_methods->get_one_authentic_pixel_from_handler;
4732}
4733
4734/*
4735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4736% %
4737% %
4738% %
4739+ S e t P i x e l C a c h e N e x u s P i x e l s %
4740% %
4741% %
4742% %
4743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4744%
4745% SetPixelCacheNexusPixels() defines the region of the cache for the
4746% specified cache nexus.
4747%
4748% The format of the SetPixelCacheNexusPixels() method is:
4749%
cristy265a2b22012-05-11 12:48:50 +00004750% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004751% const RectangleInfo *region,NexusInfo *nexus_info,
4752% ExceptionInfo *exception)
4753%
4754% A description of each parameter follows:
4755%
4756% o image: the image.
4757%
cristy265a2b22012-05-11 12:48:50 +00004758% o mode: ReadMode, WriteMode, or IOMode.
4759%
cristy3ed852e2009-09-05 21:47:34 +00004760% o region: A pointer to the RectangleInfo structure that defines the
4761% region of this particular cache nexus.
4762%
4763% o nexus_info: the cache nexus to set.
4764%
4765% o exception: return any errors or warnings in this structure.
4766%
4767*/
cristyabd6e372010-09-15 19:11:26 +00004768
cristyf1832792012-05-08 18:38:18 +00004769static inline MagickBooleanType AcquireCacheNexusPixels(
4770 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4771 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004772{
4773 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4774 return(MagickFalse);
4775 nexus_info->mapped=MagickFalse;
cristy64c3edf2012-04-13 18:50:13 +00004776 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00004777 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004778 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004779 {
4780 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004781 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004782 nexus_info->length);
4783 }
cristy4c08aed2011-07-01 19:47:50 +00004784 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004785 {
4786 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004787 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004788 cache_info->filename);
4789 return(MagickFalse);
4790 }
4791 return(MagickTrue);
4792}
4793
cristyadf82722012-05-11 17:34:16 +00004794static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4795 const MapMode mode)
4796{
cristyfc5845e2012-05-11 18:18:13 +00004797 if (mode == ReadMode)
4798 {
4799 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4800 return;
4801 }
4802 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004803}
4804
cristy265a2b22012-05-11 12:48:50 +00004805static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004806 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4807{
4808 CacheInfo
4809 *cache_info;
4810
4811 MagickBooleanType
4812 status;
4813
cristy3ed852e2009-09-05 21:47:34 +00004814 MagickSizeType
4815 length,
4816 number_pixels;
4817
cristy3ed852e2009-09-05 21:47:34 +00004818 cache_info=(CacheInfo *) image->cache;
4819 assert(cache_info->signature == MagickSignature);
4820 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004821 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004822 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004823 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004824 {
cristybb503372010-05-27 20:51:26 +00004825 ssize_t
cristybad067a2010-02-15 17:20:55 +00004826 x,
4827 y;
cristy3ed852e2009-09-05 21:47:34 +00004828
cristyeaedf062010-05-29 22:36:02 +00004829 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4830 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004831 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4832 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004833 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004834 ((nexus_info->region.width == cache_info->columns) ||
4835 ((nexus_info->region.width % cache_info->columns) == 0)))))
4836 {
4837 MagickOffsetType
4838 offset;
4839
4840 /*
4841 Pixels are accessed directly from memory.
4842 */
4843 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4844 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004845 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004846 offset;
4847 nexus_info->metacontent=(void *) NULL;
4848 if (cache_info->metacontent_extent != 0)
4849 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4850 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004851 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004852 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004853 }
4854 }
4855 /*
4856 Pixels are stored in a cache region until they are synced to the cache.
4857 */
4858 number_pixels=(MagickSizeType) nexus_info->region.width*
4859 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004860 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004861 if (cache_info->metacontent_extent != 0)
4862 length+=number_pixels*cache_info->metacontent_extent;
4863 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004864 {
4865 nexus_info->length=length;
4866 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4867 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004868 {
4869 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004870 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004871 }
cristy3ed852e2009-09-05 21:47:34 +00004872 }
4873 else
4874 if (nexus_info->length != length)
4875 {
4876 RelinquishCacheNexusPixels(nexus_info);
4877 nexus_info->length=length;
4878 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4879 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004880 {
4881 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004882 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004883 }
cristy3ed852e2009-09-05 21:47:34 +00004884 }
4885 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004886 nexus_info->metacontent=(void *) NULL;
4887 if (cache_info->metacontent_extent != 0)
4888 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004889 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004890 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004891 return(nexus_info->pixels);
4892}
4893
4894/*
4895%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4896% %
4897% %
4898% %
4899% 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 %
4900% %
4901% %
4902% %
4903%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4904%
4905% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4906% pixel cache and returns the previous setting. A virtual pixel is any pixel
4907% access that is outside the boundaries of the image cache.
4908%
4909% The format of the SetPixelCacheVirtualMethod() method is:
4910%
cristy387430f2012-02-07 13:09:46 +00004911% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4912% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004913%
4914% A description of each parameter follows:
4915%
4916% o image: the image.
4917%
4918% o virtual_pixel_method: choose the type of virtual pixel.
4919%
cristy387430f2012-02-07 13:09:46 +00004920% o exception: return any errors or warnings in this structure.
4921%
cristy3ed852e2009-09-05 21:47:34 +00004922*/
cristy3d4cb882012-02-07 19:11:26 +00004923
4924static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4925 ExceptionInfo *exception)
4926{
4927 CacheInfo
4928 *cache_info;
4929
cristyf2719112012-05-06 18:38:46 +00004930 CacheView
4931 *image_view;
4932
cristy3d4cb882012-02-07 19:11:26 +00004933 MagickBooleanType
4934 status;
4935
4936 ssize_t
4937 y;
4938
4939 assert(image != (Image *) NULL);
4940 assert(image->signature == MagickSignature);
4941 if (image->debug != MagickFalse)
4942 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4943 assert(image->cache != (Cache) NULL);
4944 cache_info=(CacheInfo *) image->cache;
4945 assert(cache_info->signature == MagickSignature);
4946 image->matte=MagickTrue;
4947 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004948 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004949#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00004950 #pragma omp parallel for schedule(static) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00004951 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004952#endif
4953 for (y=0; y < (ssize_t) image->rows; y++)
4954 {
cristy3d4cb882012-02-07 19:11:26 +00004955 register Quantum
4956 *restrict q;
4957
4958 register ssize_t
4959 x;
4960
4961 if (status == MagickFalse)
4962 continue;
cristy23d198a2012-03-13 13:48:08 +00004963 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004964 if (q == (Quantum *) NULL)
4965 {
4966 status=MagickFalse;
4967 continue;
4968 }
4969 for (x=0; x < (ssize_t) image->columns; x++)
4970 {
4971 SetPixelAlpha(image,alpha,q);
4972 q+=GetPixelChannels(image);
4973 }
cristy23d198a2012-03-13 13:48:08 +00004974 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004975 }
cristy23d198a2012-03-13 13:48:08 +00004976 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004977 return(status);
4978}
4979
cristy387430f2012-02-07 13:09:46 +00004980MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4981 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004982{
4983 CacheInfo
4984 *cache_info;
4985
4986 VirtualPixelMethod
4987 method;
4988
4989 assert(image != (Image *) NULL);
4990 assert(image->signature == MagickSignature);
4991 if (image->debug != MagickFalse)
4992 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4993 assert(image->cache != (Cache) NULL);
4994 cache_info=(CacheInfo *) image->cache;
4995 assert(cache_info->signature == MagickSignature);
4996 method=cache_info->virtual_pixel_method;
4997 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004998 switch (virtual_pixel_method)
4999 {
5000 case BackgroundVirtualPixelMethod:
5001 {
5002 if ((image->background_color.matte != MagickFalse) &&
5003 (image->matte == MagickFalse))
cristy3d4cb882012-02-07 19:11:26 +00005004 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00005005 break;
5006 }
5007 case TransparentVirtualPixelMethod:
5008 {
5009 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00005010 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00005011 break;
5012 }
5013 default:
5014 break;
5015 }
cristy3ed852e2009-09-05 21:47:34 +00005016 return(method);
5017}
5018
5019/*
5020%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5021% %
5022% %
5023% %
5024+ 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 %
5025% %
5026% %
5027% %
5028%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5029%
5030% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5031% in-memory or disk cache. The method returns MagickTrue if the pixel region
5032% is synced, otherwise MagickFalse.
5033%
5034% The format of the SyncAuthenticPixelCacheNexus() method is:
5035%
5036% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5037% NexusInfo *nexus_info,ExceptionInfo *exception)
5038%
5039% A description of each parameter follows:
5040%
5041% o image: the image.
5042%
5043% o nexus_info: the cache nexus to sync.
5044%
5045% o exception: return any errors or warnings in this structure.
5046%
5047*/
cristya6577ff2011-09-02 19:54:26 +00005048MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005049 NexusInfo *nexus_info,ExceptionInfo *exception)
5050{
5051 CacheInfo
5052 *cache_info;
5053
5054 MagickBooleanType
5055 status;
5056
5057 /*
5058 Transfer pixels to the cache.
5059 */
5060 assert(image != (Image *) NULL);
5061 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005062 if (image->cache == (Cache) NULL)
5063 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5064 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005065 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005066 if (cache_info->type == UndefinedCache)
5067 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005068 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005069 return(MagickTrue);
5070 assert(cache_info->signature == MagickSignature);
5071 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005072 if ((cache_info->metacontent_extent != 0) &&
5073 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005074 return(MagickFalse);
5075 return(status);
5076}
5077
5078/*
5079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5080% %
5081% %
5082% %
5083+ S y n c A u t h e n t i c P i x e l C a c h e %
5084% %
5085% %
5086% %
5087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5088%
5089% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5090% or disk cache. The method returns MagickTrue if the pixel region is synced,
5091% otherwise MagickFalse.
5092%
5093% The format of the SyncAuthenticPixelsCache() method is:
5094%
5095% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5096% ExceptionInfo *exception)
5097%
5098% A description of each parameter follows:
5099%
5100% o image: the image.
5101%
5102% o exception: return any errors or warnings in this structure.
5103%
5104*/
5105static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5106 ExceptionInfo *exception)
5107{
5108 CacheInfo
5109 *cache_info;
5110
cristy5c9e6f22010-09-17 17:31:01 +00005111 const int
5112 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005113
cristy4c08aed2011-07-01 19:47:50 +00005114 MagickBooleanType
5115 status;
5116
cristye7cc7cf2010-09-21 13:26:47 +00005117 assert(image != (Image *) NULL);
5118 assert(image->signature == MagickSignature);
5119 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005120 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005121 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005122 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005123 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5124 exception);
5125 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005126}
5127
5128/*
5129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5130% %
5131% %
5132% %
5133% S y n c A u t h e n t i c P i x e l s %
5134% %
5135% %
5136% %
5137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5138%
5139% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5140% The method returns MagickTrue if the pixel region is flushed, otherwise
5141% MagickFalse.
5142%
5143% The format of the SyncAuthenticPixels() method is:
5144%
5145% MagickBooleanType SyncAuthenticPixels(Image *image,
5146% ExceptionInfo *exception)
5147%
5148% A description of each parameter follows:
5149%
5150% o image: the image.
5151%
5152% o exception: return any errors or warnings in this structure.
5153%
5154*/
5155MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5156 ExceptionInfo *exception)
5157{
5158 CacheInfo
5159 *cache_info;
5160
cristy2036f5c2010-09-19 21:18:17 +00005161 const int
5162 id = GetOpenMPThreadId();
5163
cristy4c08aed2011-07-01 19:47:50 +00005164 MagickBooleanType
5165 status;
5166
cristy3ed852e2009-09-05 21:47:34 +00005167 assert(image != (Image *) NULL);
5168 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005169 assert(image->cache != (Cache) NULL);
5170 cache_info=(CacheInfo *) image->cache;
5171 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005172 if (cache_info->methods.sync_authentic_pixels_handler !=
5173 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005174 {
5175 status=cache_info->methods.sync_authentic_pixels_handler(image,
5176 exception);
5177 return(status);
5178 }
cristy2036f5c2010-09-19 21:18:17 +00005179 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005180 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5181 exception);
5182 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005183}
5184
5185/*
5186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5187% %
5188% %
5189% %
cristyd1dd6e42011-09-04 01:46:08 +00005190+ 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 +00005191% %
5192% %
5193% %
5194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5195%
5196% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5197% The method returns MagickTrue if the pixel region is flushed, otherwise
5198% MagickFalse.
5199%
5200% The format of the SyncImagePixelCache() method is:
5201%
5202% MagickBooleanType SyncImagePixelCache(Image *image,
5203% ExceptionInfo *exception)
5204%
5205% A description of each parameter follows:
5206%
5207% o image: the image.
5208%
5209% o exception: return any errors or warnings in this structure.
5210%
5211*/
cristyd1dd6e42011-09-04 01:46:08 +00005212MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005213 ExceptionInfo *exception)
5214{
5215 CacheInfo
5216 *cache_info;
5217
5218 assert(image != (Image *) NULL);
5219 assert(exception != (ExceptionInfo *) NULL);
5220 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5221 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5222}
5223
5224/*
5225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5226% %
5227% %
5228% %
cristy4c08aed2011-07-01 19:47:50 +00005229+ 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 +00005230% %
5231% %
5232% %
5233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5234%
cristy4c08aed2011-07-01 19:47:50 +00005235% WritePixelCacheMetacontent() writes the meta-content to the specified region
5236% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005237%
cristy4c08aed2011-07-01 19:47:50 +00005238% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005239%
cristy4c08aed2011-07-01 19:47:50 +00005240% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005241% NexusInfo *nexus_info,ExceptionInfo *exception)
5242%
5243% A description of each parameter follows:
5244%
5245% o cache_info: the pixel cache.
5246%
cristy4c08aed2011-07-01 19:47:50 +00005247% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005248%
5249% o exception: return any errors or warnings in this structure.
5250%
5251*/
cristy4c08aed2011-07-01 19:47:50 +00005252static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005253 NexusInfo *nexus_info,ExceptionInfo *exception)
5254{
5255 MagickOffsetType
5256 count,
5257 offset;
5258
5259 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005260 extent,
5261 length;
cristy3ed852e2009-09-05 21:47:34 +00005262
cristy4c08aed2011-07-01 19:47:50 +00005263 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005264 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005265
cristybb503372010-05-27 20:51:26 +00005266 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005267 y;
5268
cristybb503372010-05-27 20:51:26 +00005269 size_t
cristy3ed852e2009-09-05 21:47:34 +00005270 rows;
5271
cristy4c08aed2011-07-01 19:47:50 +00005272 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005273 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005274 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005275 return(MagickTrue);
5276 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5277 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005278 length=(MagickSizeType) nexus_info->region.width*
5279 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005280 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005281 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005282 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005283 switch (cache_info->type)
5284 {
5285 case MemoryCache:
5286 case MapCache:
5287 {
cristy4c08aed2011-07-01 19:47:50 +00005288 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005289 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005290
5291 /*
cristy4c08aed2011-07-01 19:47:50 +00005292 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005293 */
cristydd341db2010-03-04 19:06:38 +00005294 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005295 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005296 {
cristy48078b12010-09-23 17:11:01 +00005297 length=extent;
cristydd341db2010-03-04 19:06:38 +00005298 rows=1UL;
5299 }
cristy4c08aed2011-07-01 19:47:50 +00005300 q=(unsigned char *) cache_info->metacontent+offset*
5301 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005302 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005303 {
cristy8f036fe2010-09-18 02:02:00 +00005304 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005305 p+=nexus_info->region.width*cache_info->metacontent_extent;
5306 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005307 }
5308 break;
5309 }
5310 case DiskCache:
5311 {
5312 /*
cristy4c08aed2011-07-01 19:47:50 +00005313 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005314 */
5315 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5316 {
5317 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5318 cache_info->cache_filename);
5319 return(MagickFalse);
5320 }
cristydd341db2010-03-04 19:06:38 +00005321 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005322 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005323 {
cristy48078b12010-09-23 17:11:01 +00005324 length=extent;
cristydd341db2010-03-04 19:06:38 +00005325 rows=1UL;
5326 }
cristy48078b12010-09-23 17:11:01 +00005327 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005328 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005329 {
cristy48078b12010-09-23 17:11:01 +00005330 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005331 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005332 cache_info->metacontent_extent,length,(const unsigned char *) p);
5333 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005334 break;
cristy4c08aed2011-07-01 19:47:50 +00005335 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005336 offset+=cache_info->columns;
5337 }
cristyc11dace2012-01-24 16:39:46 +00005338 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5339 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005340 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005341 {
5342 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5343 cache_info->cache_filename);
5344 return(MagickFalse);
5345 }
5346 break;
5347 }
5348 default:
5349 break;
5350 }
5351 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005352 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005353 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005354 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005355 nexus_info->region.width,(double) nexus_info->region.height,(double)
5356 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005357 return(MagickTrue);
5358}
5359
5360/*
5361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5362% %
5363% %
5364% %
5365+ W r i t e C a c h e P i x e l s %
5366% %
5367% %
5368% %
5369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5370%
5371% WritePixelCachePixels() writes image pixels to the specified region of the
5372% pixel cache.
5373%
5374% The format of the WritePixelCachePixels() method is:
5375%
5376% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5377% NexusInfo *nexus_info,ExceptionInfo *exception)
5378%
5379% A description of each parameter follows:
5380%
5381% o cache_info: the pixel cache.
5382%
5383% o nexus_info: the cache nexus to write the pixels.
5384%
5385% o exception: return any errors or warnings in this structure.
5386%
5387*/
5388static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5389 NexusInfo *nexus_info,ExceptionInfo *exception)
5390{
5391 MagickOffsetType
5392 count,
5393 offset;
5394
5395 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005396 extent,
5397 length;
cristy3ed852e2009-09-05 21:47:34 +00005398
cristy4c08aed2011-07-01 19:47:50 +00005399 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005400 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005401
cristybb503372010-05-27 20:51:26 +00005402 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005403 y;
5404
cristybb503372010-05-27 20:51:26 +00005405 size_t
cristy3ed852e2009-09-05 21:47:34 +00005406 rows;
5407
cristy4c08aed2011-07-01 19:47:50 +00005408 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005409 return(MagickTrue);
5410 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5411 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005412 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005413 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005414 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005415 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005416 p=nexus_info->pixels;
5417 switch (cache_info->type)
5418 {
5419 case MemoryCache:
5420 case MapCache:
5421 {
cristy4c08aed2011-07-01 19:47:50 +00005422 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005423 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005424
5425 /*
5426 Write pixels to memory.
5427 */
cristydd341db2010-03-04 19:06:38 +00005428 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005429 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005430 {
cristy48078b12010-09-23 17:11:01 +00005431 length=extent;
cristydd341db2010-03-04 19:06:38 +00005432 rows=1UL;
5433 }
cristyed231572011-07-14 02:18:59 +00005434 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005435 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005436 {
cristy8f036fe2010-09-18 02:02:00 +00005437 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005438 p+=nexus_info->region.width*cache_info->number_channels;
5439 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005440 }
5441 break;
5442 }
5443 case DiskCache:
5444 {
5445 /*
5446 Write pixels to disk.
5447 */
5448 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5449 {
5450 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5451 cache_info->cache_filename);
5452 return(MagickFalse);
5453 }
cristydd341db2010-03-04 19:06:38 +00005454 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005455 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005456 {
cristy48078b12010-09-23 17:11:01 +00005457 length=extent;
cristydd341db2010-03-04 19:06:38 +00005458 rows=1UL;
5459 }
cristybb503372010-05-27 20:51:26 +00005460 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005461 {
5462 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005463 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005464 p);
5465 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005466 break;
cristyed231572011-07-14 02:18:59 +00005467 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005468 offset+=cache_info->columns;
5469 }
cristyc11dace2012-01-24 16:39:46 +00005470 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5471 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005472 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005473 {
5474 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5475 cache_info->cache_filename);
5476 return(MagickFalse);
5477 }
5478 break;
5479 }
5480 default:
5481 break;
5482 }
5483 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005484 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005485 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005486 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005487 nexus_info->region.width,(double) nexus_info->region.height,(double)
5488 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005489 return(MagickTrue);
5490}