blob: 017722a439c76ba3134ad3af5e8faac2d9b19da4 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
cristyadf82722012-05-11 17:34:16 +000057#include "MagickCore/memory-private.h"
cristyd2d11ec2012-03-28 13:53:49 +000058#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000059#include "MagickCore/pixel.h"
60#include "MagickCore/pixel-accessor.h"
61#include "MagickCore/policy.h"
62#include "MagickCore/quantum.h"
63#include "MagickCore/random_.h"
64#include "MagickCore/resource_.h"
65#include "MagickCore/semaphore.h"
66#include "MagickCore/splay-tree.h"
67#include "MagickCore/string_.h"
68#include "MagickCore/string-private.h"
69#include "MagickCore/thread-private.h"
70#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000071#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000072#if defined(MAGICKCORE_ZLIB_DELEGATE)
73#include "zlib.h"
74#endif
75
76/*
cristy30097232010-07-01 02:16:30 +000077 Define declarations.
78*/
79#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
cristyc11dace2012-01-24 16:39:46 +000080#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
81 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
cristy30097232010-07-01 02:16:30 +000082
83/*
cristy3ed852e2009-09-05 21:47:34 +000084 Typedef declarations.
85*/
86typedef struct _MagickModulo
87{
cristybb503372010-05-27 20:51:26 +000088 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000089 quotient,
90 remainder;
91} MagickModulo;
92
93struct _NexusInfo
94{
95 MagickBooleanType
96 mapped;
97
98 RectangleInfo
99 region;
100
101 MagickSizeType
102 length;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000105 *cache,
106 *pixels;
107
cristy4c08aed2011-07-01 19:47:50 +0000108 void
109 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000110
cristybb503372010-05-27 20:51:26 +0000111 size_t
cristy3ed852e2009-09-05 21:47:34 +0000112 signature;
113};
114
115/*
116 Forward declarations.
117*/
118#if defined(__cplusplus) || defined(c_plusplus)
119extern "C" {
120#endif
121
cristy19596d62012-02-19 00:24:59 +0000122static Cache
123 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
124 magick_hot_spot;
125
cristy4c08aed2011-07-01 19:47:50 +0000126static const Quantum
cristybb503372010-05-27 20:51:26 +0000127 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000128 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000129 *GetVirtualPixelsCache(const Image *);
130
cristy4c08aed2011-07-01 19:47:50 +0000131static const void
132 *GetVirtualMetacontentFromCache(const Image *);
133
cristy3ed852e2009-09-05 21:47:34 +0000134static MagickBooleanType
cristy74ce05d2012-05-06 18:41:18 +0000135 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
136 ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000137 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000138 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000139 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000140 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000141 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
142 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000143 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000144 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
145
cristy4c08aed2011-07-01 19:47:50 +0000146static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000147 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
148 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000149 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
150 const size_t,ExceptionInfo *),
cristy265a2b22012-05-11 12:48:50 +0000151 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
152 NexusInfo *,ExceptionInfo *) magick_hot_spot;
cristy3ed852e2009-09-05 21:47:34 +0000153
154#if defined(__cplusplus) || defined(c_plusplus)
155}
156#endif
157
158/*
159 Global declarations.
160*/
161static volatile MagickBooleanType
162 instantiate_cache = MagickFalse;
163
164static SemaphoreInfo
165 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000166
167/*
168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169% %
170% %
171% %
172+ A c q u i r e P i x e l C a c h e %
173% %
174% %
175% %
176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177%
178% AcquirePixelCache() acquires a pixel cache.
179%
180% The format of the AcquirePixelCache() method is:
181%
cristybb503372010-05-27 20:51:26 +0000182% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000183%
184% A description of each parameter follows:
185%
186% o number_threads: the number of nexus threads.
187%
188*/
cristya6577ff2011-09-02 19:54:26 +0000189MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000190{
191 CacheInfo
192 *cache_info;
193
cristya64b85d2011-09-14 01:02:31 +0000194 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000195 if (cache_info == (CacheInfo *) NULL)
196 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
197 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
198 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000199 cache_info->mode=IOMode;
cristyc511e882012-04-16 21:11:14 +0000200 cache_info->colorspace=sRGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +0000201 cache_info->file=(-1);
202 cache_info->id=GetMagickThreadId();
203 cache_info->number_threads=number_threads;
204 if (number_threads == 0)
cristyfeeb98d2012-05-09 16:32:12 +0000205 cache_info->number_threads=GetOpenMPMaximumThreads();
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
207 if (cache_info->nexus_info == (NexusInfo **) NULL)
208 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000209 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000210 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000211 cache_info->disk_semaphore=AllocateSemaphoreInfo();
212 cache_info->debug=IsEventLogging();
213 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000214 return((Cache ) cache_info);
215}
216
217/*
218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219% %
220% %
221% %
222% A c q u i r e P i x e l C a c h e N e x u s %
223% %
224% %
225% %
226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227%
228% AcquirePixelCacheNexus() allocates the NexusInfo structure.
229%
230% The format of the AcquirePixelCacheNexus method is:
231%
cristybb503372010-05-27 20:51:26 +0000232% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000233%
234% A description of each parameter follows:
235%
236% o number_threads: the number of nexus threads.
237%
238*/
cristya6577ff2011-09-02 19:54:26 +0000239MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000240{
cristy3ed852e2009-09-05 21:47:34 +0000241 NexusInfo
242 **nexus_info;
243
cristye076a6e2010-08-15 19:59:43 +0000244 register ssize_t
245 i;
246
cristy64c3edf2012-04-13 18:50:13 +0000247 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000248 sizeof(*nexus_info));
249 if (nexus_info == (NexusInfo **) NULL)
250 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000251 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
252 sizeof(**nexus_info));
253 if (nexus_info[0] == (NexusInfo *) NULL)
254 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
255 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000256 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000257 {
cristye5f87c82012-02-14 12:44:17 +0000258 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000259 nexus_info[i]->signature=MagickSignature;
260 }
261 return(nexus_info);
262}
263
264/*
265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266% %
267% %
268% %
cristyd43a46b2010-01-21 02:13:41 +0000269+ A c q u i r e P i x e l C a c h e P i x e l s %
270% %
271% %
272% %
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274%
275% AcquirePixelCachePixels() returns the pixels associated with the specified
276% image.
277%
278% The format of the AcquirePixelCachePixels() method is:
279%
280% const void *AcquirePixelCachePixels(const Image *image,
281% MagickSizeType *length,ExceptionInfo *exception)
282%
283% A description of each parameter follows:
284%
285% o image: the image.
286%
287% o length: the pixel cache length.
288%
289% o exception: return any errors or warnings in this structure.
290%
291*/
cristyd1dd6e42011-09-04 01:46:08 +0000292MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000293 MagickSizeType *length,ExceptionInfo *exception)
294{
295 CacheInfo
296 *cache_info;
297
298 assert(image != (const Image *) NULL);
299 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000300 assert(exception != (ExceptionInfo *) NULL);
301 assert(exception->signature == MagickSignature);
302 assert(image->cache != (Cache) NULL);
303 cache_info=(CacheInfo *) image->cache;
304 assert(cache_info->signature == MagickSignature);
305 *length=0;
306 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
307 return((const void *) NULL);
308 *length=cache_info->length;
309 return((const void *) cache_info->pixels);
310}
311
312/*
313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314% %
315% %
316% %
cristyf34a1452009-10-24 22:29:27 +0000317+ C a c h e C o m p o n e n t G e n e s i s %
318% %
319% %
320% %
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322%
323% CacheComponentGenesis() instantiates the cache component.
324%
325% The format of the CacheComponentGenesis method is:
326%
327% MagickBooleanType CacheComponentGenesis(void)
328%
329*/
cristy5ff4eaf2011-09-03 01:38:02 +0000330MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000331{
cristy165b6092009-10-26 13:52:10 +0000332 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000333 return(MagickTrue);
334}
335
336/*
337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338% %
339% %
340% %
341+ C a c h e C o m p o n e n t T e r m i n u s %
342% %
343% %
344% %
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346%
347% CacheComponentTerminus() destroys the cache component.
348%
349% The format of the CacheComponentTerminus() method is:
350%
351% CacheComponentTerminus(void)
352%
353*/
cristy5ff4eaf2011-09-03 01:38:02 +0000354MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000355{
cristy18b17442009-10-25 18:36:48 +0000356 if (cache_semaphore == (SemaphoreInfo *) NULL)
357 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000358 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000359 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000360 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000361 DestroySemaphoreInfo(&cache_semaphore);
362}
363
364/*
365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366% %
367% %
368% %
cristy3ed852e2009-09-05 21:47:34 +0000369+ C l o n e P i x e l C a c h e %
370% %
371% %
372% %
373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374%
375% ClonePixelCache() clones a pixel cache.
376%
377% The format of the ClonePixelCache() method is:
378%
379% Cache ClonePixelCache(const Cache cache)
380%
381% A description of each parameter follows:
382%
383% o cache: the pixel cache.
384%
385*/
cristya6577ff2011-09-02 19:54:26 +0000386MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000387{
388 CacheInfo
389 *clone_info;
390
391 const CacheInfo
392 *cache_info;
393
cristy9f027d12011-09-21 01:17:17 +0000394 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000395 cache_info=(const CacheInfo *) cache;
396 assert(cache_info->signature == MagickSignature);
397 if (cache_info->debug != MagickFalse)
398 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
399 cache_info->filename);
400 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
401 if (clone_info == (Cache) NULL)
402 return((Cache) NULL);
403 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
404 return((Cache ) clone_info);
405}
406
407/*
408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
409% %
410% %
411% %
cristy60c44a82009-10-07 00:58:49 +0000412+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000413% %
414% %
415% %
416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
417% ClonePixelCachePixels() clones the source pixel cache to the destination
418% cache.
419%
420% The format of the ClonePixelCachePixels() method is:
421%
422% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
423% CacheInfo *source_info,ExceptionInfo *exception)
424%
425% A description of each parameter follows:
426%
427% o cache_info: the pixel cache.
428%
429% o source_info: the source pixel cache.
430%
431% o exception: return any errors or warnings in this structure.
432%
433*/
434
435static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
436{
437 int
438 status;
439
cristy5ee247a2010-02-12 15:42:34 +0000440 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000441 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000442 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000443 {
444 status=close(cache_info->file);
445 cache_info->file=(-1);
446 RelinquishMagickResource(FileResource,1);
447 }
cristyf84a1932010-01-03 18:00:18 +0000448 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000449 return(status == -1 ? MagickFalse : MagickTrue);
450}
451
cristy3ed852e2009-09-05 21:47:34 +0000452static inline MagickSizeType MagickMax(const MagickSizeType x,
453 const MagickSizeType y)
454{
455 if (x > y)
456 return(x);
457 return(y);
458}
459
460static inline MagickSizeType MagickMin(const MagickSizeType x,
461 const MagickSizeType y)
462{
463 if (x < y)
464 return(x);
465 return(y);
466}
467
468static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
469 const MapMode mode)
470{
471 int
472 file;
473
474 /*
475 Open pixel cache on disk.
476 */
cristyf84a1932010-01-03 18:00:18 +0000477 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000478 if (cache_info->file != -1)
479 {
cristyf84a1932010-01-03 18:00:18 +0000480 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000481 return(MagickTrue); /* cache already open */
482 }
cristy3ed852e2009-09-05 21:47:34 +0000483 if (*cache_info->cache_filename == '\0')
484 file=AcquireUniqueFileResource(cache_info->cache_filename);
485 else
486 switch (mode)
487 {
488 case ReadMode:
489 {
cristy18c6c272011-09-23 14:40:37 +0000490 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000491 break;
492 }
493 case WriteMode:
494 {
cristy18c6c272011-09-23 14:40:37 +0000495 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
496 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000497 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000498 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000499 break;
500 }
501 case IOMode:
502 default:
503 {
cristy18c6c272011-09-23 14:40:37 +0000504 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000505 O_EXCL,S_MODE);
506 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000507 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000508 break;
509 }
510 }
511 if (file == -1)
512 {
cristyf84a1932010-01-03 18:00:18 +0000513 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000514 return(MagickFalse);
515 }
516 (void) AcquireMagickResource(FileResource,1);
517 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000518 cache_info->mode=mode;
cristyf84a1932010-01-03 18:00:18 +0000519 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000520 return(MagickTrue);
521}
522
cristyf1832792012-05-08 18:38:18 +0000523static inline MagickOffsetType ReadPixelCacheRegion(
524 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
525 const MagickSizeType length,unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000526{
527 register MagickOffsetType
528 i;
529
530 ssize_t
531 count;
532
533#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000534 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000535 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000536 {
cristyf84a1932010-01-03 18:00:18 +0000537 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000538 return((MagickOffsetType) -1);
539 }
540#endif
541 count=0;
542 for (i=0; i < (MagickOffsetType) length; i+=count)
543 {
544#if !defined(MAGICKCORE_HAVE_PREAD)
545 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
546 (MagickSizeType) SSIZE_MAX));
547#else
548 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000549 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000550#endif
551 if (count > 0)
552 continue;
553 count=0;
554 if (errno != EINTR)
555 {
556 i=(-1);
557 break;
558 }
559 }
560#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000561 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000562#endif
563 return(i);
564}
565
cristyf1832792012-05-08 18:38:18 +0000566static inline MagickOffsetType WritePixelCacheRegion(
567 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
568 const MagickSizeType length,const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000569{
570 register MagickOffsetType
571 i;
572
573 ssize_t
574 count;
575
576#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000578 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return((MagickOffsetType) -1);
582 }
583#endif
584 count=0;
585 for (i=0; i < (MagickOffsetType) length; i+=count)
586 {
587#if !defined(MAGICKCORE_HAVE_PWRITE)
588 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
589 (MagickSizeType) SSIZE_MAX));
590#else
591 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000592 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000593#endif
594 if (count > 0)
595 continue;
596 count=0;
597 if (errno != EINTR)
598 {
599 i=(-1);
600 break;
601 }
602 }
603#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000604 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000605#endif
606 return(i);
607}
608
cristy4c08aed2011-07-01 19:47:50 +0000609static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000610 CacheInfo *cache_info,ExceptionInfo *exception)
611{
612 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000613 count;
cristy3ed852e2009-09-05 21:47:34 +0000614
cristy4c08aed2011-07-01 19:47:50 +0000615 register MagickOffsetType
616 i;
cristye076a6e2010-08-15 19:59:43 +0000617
cristybb503372010-05-27 20:51:26 +0000618 size_t
cristy4c08aed2011-07-01 19:47:50 +0000619 length;
cristy3ed852e2009-09-05 21:47:34 +0000620
cristy4c08aed2011-07-01 19:47:50 +0000621 unsigned char
622 *blob;
623
624 /*
625 Clone pixel cache (both caches on disk).
626 */
cristy3ed852e2009-09-05 21:47:34 +0000627 if (cache_info->debug != MagickFalse)
628 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000629 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000630 sizeof(*blob));
631 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000632 {
cristy4c08aed2011-07-01 19:47:50 +0000633 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000634 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000635 cache_info->filename);
636 return(MagickFalse);
637 }
cristy3dedf062011-07-02 14:07:40 +0000638 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000639 {
640 blob=(unsigned char *) RelinquishMagickMemory(blob);
641 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
642 cache_info->cache_filename);
643 return(MagickFalse);
644 }
cristy3dedf062011-07-02 14:07:40 +0000645 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000646 {
647 (void) ClosePixelCacheOnDisk(cache_info);
648 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000649 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
650 clone_info->cache_filename);
651 return(MagickFalse);
652 }
cristy4c08aed2011-07-01 19:47:50 +0000653 count=0;
654 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000655 {
cristy4c08aed2011-07-01 19:47:50 +0000656 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
657 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
658 blob);
659 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000660 {
cristy4c08aed2011-07-01 19:47:50 +0000661 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
662 cache_info->cache_filename);
663 break;
cristy3ed852e2009-09-05 21:47:34 +0000664 }
cristy4c08aed2011-07-01 19:47:50 +0000665 length=(size_t) count;
666 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
667 if ((MagickSizeType) count != length)
668 {
669 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
670 clone_info->cache_filename);
671 break;
672 }
673 }
674 (void) ClosePixelCacheOnDisk(clone_info);
675 (void) ClosePixelCacheOnDisk(cache_info);
676 blob=(unsigned char *) RelinquishMagickMemory(blob);
677 if (i < (MagickOffsetType) cache_info->length)
678 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000679 return(MagickTrue);
680}
681
cristyfd24a062012-01-02 14:46:34 +0000682static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000683 CacheInfo *cache_info,ExceptionInfo *exception)
684{
685 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000686 count;
cristy3ed852e2009-09-05 21:47:34 +0000687
cristy4c08aed2011-07-01 19:47:50 +0000688 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000689 {
cristy3ed852e2009-09-05 21:47:34 +0000690 /*
cristy4c08aed2011-07-01 19:47:50 +0000691 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000692 */
cristy4c08aed2011-07-01 19:47:50 +0000693 if (cache_info->debug != MagickFalse)
694 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
695 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
696 cache_info->length);
697 return(MagickTrue);
698 }
699 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
700 {
701 /*
702 Clone pixel cache (one cache on disk, one in memory).
703 */
704 if (cache_info->debug != MagickFalse)
705 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
706 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000707 {
cristy4c08aed2011-07-01 19:47:50 +0000708 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000709 cache_info->cache_filename);
710 return(MagickFalse);
711 }
cristy4c08aed2011-07-01 19:47:50 +0000712 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
713 cache_info->length,(unsigned char *) clone_info->pixels);
714 (void) ClosePixelCacheOnDisk(cache_info);
715 if ((MagickSizeType) count != cache_info->length)
716 {
717 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
718 cache_info->cache_filename);
719 return(MagickFalse);
720 }
721 return(MagickTrue);
722 }
723 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
724 {
725 /*
726 Clone pixel cache (one cache on disk, one in memory).
727 */
728 if (clone_info->debug != MagickFalse)
729 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
730 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
731 {
732 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
733 clone_info->cache_filename);
734 return(MagickFalse);
735 }
736 count=WritePixelCacheRegion(clone_info,clone_info->offset,
737 clone_info->length,(unsigned char *) cache_info->pixels);
738 (void) ClosePixelCacheOnDisk(clone_info);
739 if ((MagickSizeType) count != clone_info->length)
740 {
741 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
742 clone_info->cache_filename);
743 return(MagickFalse);
744 }
745 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000746 }
747 /*
cristy4c08aed2011-07-01 19:47:50 +0000748 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000749 */
cristy4c08aed2011-07-01 19:47:50 +0000750 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000751}
752
cristyfd24a062012-01-02 14:46:34 +0000753static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000754 CacheInfo *cache_info,ExceptionInfo *exception)
755{
cristy4c08aed2011-07-01 19:47:50 +0000756 MagickBooleanType
757 status;
cristy3ed852e2009-09-05 21:47:34 +0000758
cristy4c08aed2011-07-01 19:47:50 +0000759 MagickOffsetType
760 cache_offset,
761 clone_offset,
762 count;
763
764 register ssize_t
765 x;
766
cristyfd24a062012-01-02 14:46:34 +0000767 register unsigned char
768 *p;
769
cristy4c08aed2011-07-01 19:47:50 +0000770 size_t
cristy3ed852e2009-09-05 21:47:34 +0000771 length;
772
cristy4c08aed2011-07-01 19:47:50 +0000773 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000774 y;
775
cristy4c08aed2011-07-01 19:47:50 +0000776 unsigned char
777 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000778
cristy4c08aed2011-07-01 19:47:50 +0000779 /*
780 Clone pixel cache (unoptimized).
781 */
cristy3ed852e2009-09-05 21:47:34 +0000782 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000783 {
cristy4c08aed2011-07-01 19:47:50 +0000784 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
786 else
787 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
789 else
790 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
792 else
793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
794 }
cristyed231572011-07-14 02:18:59 +0000795 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
796 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000797 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000798 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000799 if (blob == (unsigned char *) NULL)
800 {
801 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000802 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000803 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000804 return(MagickFalse);
805 }
cristy4c08aed2011-07-01 19:47:50 +0000806 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
807 cache_offset=0;
808 clone_offset=0;
809 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000810 {
cristy4c08aed2011-07-01 19:47:50 +0000811 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 blob=(unsigned char *) RelinquishMagickMemory(blob);
814 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000815 cache_info->cache_filename);
816 return(MagickFalse);
817 }
cristy4c08aed2011-07-01 19:47:50 +0000818 cache_offset=cache_info->offset;
819 }
820 if (clone_info->type == DiskCache)
821 {
cristy3dedf062011-07-02 14:07:40 +0000822 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000823 {
cristy4c08aed2011-07-01 19:47:50 +0000824 blob=(unsigned char *) RelinquishMagickMemory(blob);
825 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
826 clone_info->cache_filename);
827 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000828 }
cristy4c08aed2011-07-01 19:47:50 +0000829 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000830 }
831 /*
cristy4c08aed2011-07-01 19:47:50 +0000832 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000833 */
cristy4c08aed2011-07-01 19:47:50 +0000834 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000835 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000836 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000837 {
cristy4c08aed2011-07-01 19:47:50 +0000838 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000839 {
cristy9e0719b2011-12-29 03:45:45 +0000840 register ssize_t
841 i;
842
cristy3ed852e2009-09-05 21:47:34 +0000843 /*
cristy4c08aed2011-07-01 19:47:50 +0000844 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000845 */
cristyed231572011-07-14 02:18:59 +0000846 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000847 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000848 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000849 else
850 {
cristyfd24a062012-01-02 14:46:34 +0000851 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000852 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000853 {
cristy4c08aed2011-07-01 19:47:50 +0000854 status=MagickFalse;
855 break;
cristy3ed852e2009-09-05 21:47:34 +0000856 }
857 }
cristy4c08aed2011-07-01 19:47:50 +0000858 cache_offset+=length;
859 if ((y < (ssize_t) clone_info->rows) &&
860 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000861 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000862 {
cristy9e0719b2011-12-29 03:45:45 +0000863 PixelChannel
864 channel;
865
866 PixelTrait
867 traits;
868
869 ssize_t
870 offset;
871
cristy4c08aed2011-07-01 19:47:50 +0000872 /*
cristy3b8fe922011-12-29 18:56:23 +0000873 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000874 */
cristy9e0719b2011-12-29 03:45:45 +0000875 channel=clone_info->channel_map[i].channel;
876 traits=cache_info->channel_map[channel].traits;
877 if (traits == UndefinedPixelTrait)
878 {
cristy0f4425e2011-12-31 20:33:02 +0000879 clone_offset+=sizeof(Quantum);
880 continue;
cristy9e0719b2011-12-29 03:45:45 +0000881 }
cristy0f4425e2011-12-31 20:33:02 +0000882 offset=cache_info->channel_map[channel].offset;
883 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000884 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
885 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000886 else
887 {
cristy0f4425e2011-12-31 20:33:02 +0000888 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000889 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000890 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000891 {
cristy0f4425e2011-12-31 20:33:02 +0000892 status=MagickFalse;
893 break;
cristy4c08aed2011-07-01 19:47:50 +0000894 }
895 }
cristy9e0719b2011-12-29 03:45:45 +0000896 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000897 }
898 }
cristyac245f82012-05-05 17:13:57 +0000899 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000900 {
901 /*
902 Set remaining columns as undefined.
903 */
cristy888e6132012-04-23 19:54:54 +0000904 length=clone_info->number_channels*sizeof(Quantum);
905 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
906 for ( ; x < (ssize_t) clone_info->columns; x++)
907 {
908 if (clone_info->type != DiskCache)
909 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
910 blob,length);
911 else
912 {
913 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
914 if ((MagickSizeType) count != length)
915 {
916 status=MagickFalse;
917 break;
cristye04362f2012-04-23 15:33:05 +0000918 }
cristy888e6132012-04-23 19:54:54 +0000919 }
920 clone_offset+=length;
921 }
cristye04362f2012-04-23 15:33:05 +0000922 }
cristy4c08aed2011-07-01 19:47:50 +0000923 }
cristyed231572011-07-14 02:18:59 +0000924 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000925 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
926 for ( ; y < (ssize_t) clone_info->rows; y++)
927 {
928 /*
cristy9e0719b2011-12-29 03:45:45 +0000929 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000930 */
931 for (x=0; x < (ssize_t) clone_info->columns; x++)
932 {
933 if (clone_info->type != DiskCache)
934 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
935 length);
936 else
937 {
938 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
939 if ((MagickSizeType) count != length)
940 {
941 status=MagickFalse;
942 break;
943 }
944 }
945 clone_offset+=length;
946 }
947 }
cristy9e0719b2011-12-29 03:45:45 +0000948 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000949 (clone_info->metacontent_extent != 0))
950 {
951 /*
952 Clone metacontent.
953 */
954 for (y=0; y < (ssize_t) cache_info->rows; y++)
955 {
956 for (x=0; x < (ssize_t) cache_info->columns; x++)
957 {
958 /*
959 Read a set of metacontent.
960 */
961 length=cache_info->metacontent_extent;
962 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000963 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000964 else
965 {
cristyfd24a062012-01-02 14:46:34 +0000966 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000967 if ((MagickSizeType) count != length)
968 {
969 status=MagickFalse;
970 break;
971 }
972 }
973 cache_offset+=length;
974 if ((y < (ssize_t) clone_info->rows) &&
975 (x < (ssize_t) clone_info->columns))
976 {
977 /*
978 Write a set of metacontent.
979 */
980 length=clone_info->metacontent_extent;
981 if (clone_info->type != DiskCache)
982 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000983 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000984 else
985 {
cristyfd24a062012-01-02 14:46:34 +0000986 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000987 if ((MagickSizeType) count != length)
988 {
989 status=MagickFalse;
990 break;
991 }
992 }
993 clone_offset+=length;
994 }
995 }
996 length=clone_info->metacontent_extent;
997 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
998 for ( ; x < (ssize_t) clone_info->columns; x++)
999 {
1000 /*
cristy9e0719b2011-12-29 03:45:45 +00001001 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001002 */
1003 if (clone_info->type != DiskCache)
1004 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1005 blob,length);
1006 else
1007 {
cristy208b1002011-08-07 18:51:50 +00001008 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001009 if ((MagickSizeType) count != length)
1010 {
1011 status=MagickFalse;
1012 break;
1013 }
1014 }
1015 clone_offset+=length;
1016 }
1017 }
cristyac245f82012-05-05 17:13:57 +00001018 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001019 {
cristye04362f2012-04-23 15:33:05 +00001020 /*
1021 Set remaining rows as undefined.
1022 */
cristy888e6132012-04-23 19:54:54 +00001023 length=clone_info->metacontent_extent;
1024 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1025 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001026 {
cristy888e6132012-04-23 19:54:54 +00001027 for (x=0; x < (ssize_t) clone_info->columns; x++)
1028 {
1029 if (clone_info->type != DiskCache)
1030 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1031 blob,length);
1032 else
1033 {
1034 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1035 blob);
1036 if ((MagickSizeType) count != length)
1037 {
1038 status=MagickFalse;
1039 break;
1040 }
1041 }
1042 clone_offset+=length;
1043 }
cristye04362f2012-04-23 15:33:05 +00001044 }
cristy4c08aed2011-07-01 19:47:50 +00001045 }
cristy4c08aed2011-07-01 19:47:50 +00001046 }
1047 if (clone_info->type == DiskCache)
1048 (void) ClosePixelCacheOnDisk(clone_info);
1049 if (cache_info->type == DiskCache)
1050 (void) ClosePixelCacheOnDisk(cache_info);
1051 blob=(unsigned char *) RelinquishMagickMemory(blob);
1052 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001053}
1054
1055static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1056 CacheInfo *cache_info,ExceptionInfo *exception)
1057{
cristy3dfccb22011-12-28 21:47:20 +00001058 PixelChannelMap
1059 *p,
1060 *q;
1061
cristy5a7fbfb2010-11-06 16:10:59 +00001062 if (cache_info->type == PingCache)
1063 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001064 p=cache_info->channel_map;
1065 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001066 if ((cache_info->columns == clone_info->columns) &&
1067 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001068 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001069 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001070 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001071 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1072 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001073}
1074
1075/*
1076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1077% %
1078% %
1079% %
1080+ C l o n e P i x e l C a c h e M e t h o d s %
1081% %
1082% %
1083% %
1084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1085%
1086% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1087% another.
1088%
1089% The format of the ClonePixelCacheMethods() method is:
1090%
1091% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1092%
1093% A description of each parameter follows:
1094%
1095% o clone: Specifies a pointer to a Cache structure.
1096%
1097% o cache: the pixel cache.
1098%
1099*/
cristya6577ff2011-09-02 19:54:26 +00001100MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001101{
1102 CacheInfo
1103 *cache_info,
1104 *source_info;
1105
1106 assert(clone != (Cache) NULL);
1107 source_info=(CacheInfo *) clone;
1108 assert(source_info->signature == MagickSignature);
1109 if (source_info->debug != MagickFalse)
1110 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1111 source_info->filename);
1112 assert(cache != (Cache) NULL);
1113 cache_info=(CacheInfo *) cache;
1114 assert(cache_info->signature == MagickSignature);
1115 source_info->methods=cache_info->methods;
1116}
1117
1118/*
1119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1120% %
1121% %
1122% %
1123+ D e s t r o y I m a g e P i x e l C a c h e %
1124% %
1125% %
1126% %
1127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1128%
1129% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1130%
1131% The format of the DestroyImagePixelCache() method is:
1132%
1133% void DestroyImagePixelCache(Image *image)
1134%
1135% A description of each parameter follows:
1136%
1137% o image: the image.
1138%
1139*/
1140static void DestroyImagePixelCache(Image *image)
1141{
1142 assert(image != (Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 if (image->debug != MagickFalse)
1145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1146 if (image->cache == (void *) NULL)
1147 return;
1148 image->cache=DestroyPixelCache(image->cache);
1149}
1150
1151/*
1152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1153% %
1154% %
1155% %
1156+ D e s t r o y I m a g e P i x e l s %
1157% %
1158% %
1159% %
1160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1161%
1162% DestroyImagePixels() deallocates memory associated with the pixel cache.
1163%
1164% The format of the DestroyImagePixels() method is:
1165%
1166% void DestroyImagePixels(Image *image)
1167%
1168% A description of each parameter follows:
1169%
1170% o image: the image.
1171%
1172*/
1173MagickExport void DestroyImagePixels(Image *image)
1174{
1175 CacheInfo
1176 *cache_info;
1177
1178 assert(image != (const Image *) NULL);
1179 assert(image->signature == MagickSignature);
1180 if (image->debug != MagickFalse)
1181 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1182 assert(image->cache != (Cache) NULL);
1183 cache_info=(CacheInfo *) image->cache;
1184 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001185 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1186 {
1187 cache_info->methods.destroy_pixel_handler(image);
1188 return;
1189 }
cristy2036f5c2010-09-19 21:18:17 +00001190 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001191}
1192
1193/*
1194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1195% %
1196% %
1197% %
1198+ D e s t r o y P i x e l C a c h e %
1199% %
1200% %
1201% %
1202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203%
1204% DestroyPixelCache() deallocates memory associated with the pixel cache.
1205%
1206% The format of the DestroyPixelCache() method is:
1207%
1208% Cache DestroyPixelCache(Cache cache)
1209%
1210% A description of each parameter follows:
1211%
1212% o cache: the pixel cache.
1213%
1214*/
1215
1216static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1217{
1218 switch (cache_info->type)
1219 {
1220 case MemoryCache:
1221 {
1222 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001223 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001224 cache_info->pixels);
1225 else
cristy4c08aed2011-07-01 19:47:50 +00001226 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001227 (size_t) cache_info->length);
1228 RelinquishMagickResource(MemoryResource,cache_info->length);
1229 break;
1230 }
1231 case MapCache:
1232 {
cristy4c08aed2011-07-01 19:47:50 +00001233 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001234 cache_info->length);
1235 RelinquishMagickResource(MapResource,cache_info->length);
1236 }
1237 case DiskCache:
1238 {
1239 if (cache_info->file != -1)
1240 (void) ClosePixelCacheOnDisk(cache_info);
1241 RelinquishMagickResource(DiskResource,cache_info->length);
1242 break;
1243 }
1244 default:
1245 break;
1246 }
1247 cache_info->type=UndefinedCache;
1248 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001249 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001250}
1251
cristya6577ff2011-09-02 19:54:26 +00001252MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001253{
1254 CacheInfo
1255 *cache_info;
1256
cristy3ed852e2009-09-05 21:47:34 +00001257 assert(cache != (Cache) NULL);
1258 cache_info=(CacheInfo *) cache;
1259 assert(cache_info->signature == MagickSignature);
1260 if (cache_info->debug != MagickFalse)
1261 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1262 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001263 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001264 cache_info->reference_count--;
1265 if (cache_info->reference_count != 0)
1266 {
cristyf84a1932010-01-03 18:00:18 +00001267 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001268 return((Cache) NULL);
1269 }
cristyf84a1932010-01-03 18:00:18 +00001270 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001271 if (cache_info->debug != MagickFalse)
1272 {
1273 char
1274 message[MaxTextExtent];
1275
cristyb51dff52011-05-19 16:55:47 +00001276 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001277 cache_info->filename);
1278 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1279 }
cristyc2e1bdd2009-09-10 23:43:34 +00001280 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1281 (cache_info->type != DiskCache)))
1282 RelinquishPixelCachePixels(cache_info);
1283 else
1284 {
1285 RelinquishPixelCachePixels(cache_info);
1286 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1287 }
cristy3ed852e2009-09-05 21:47:34 +00001288 *cache_info->cache_filename='\0';
1289 if (cache_info->nexus_info != (NexusInfo **) NULL)
1290 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1291 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001292 if (cache_info->random_info != (RandomInfo *) NULL)
1293 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001294 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1295 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1296 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1297 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001298 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001299 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001300 cache=(Cache) NULL;
1301 return(cache);
1302}
1303
1304/*
1305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1306% %
1307% %
1308% %
1309+ D e s t r o y P i x e l C a c h e N e x u s %
1310% %
1311% %
1312% %
1313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1314%
1315% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1316%
1317% The format of the DestroyPixelCacheNexus() method is:
1318%
1319% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001320% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001321%
1322% A description of each parameter follows:
1323%
1324% o nexus_info: the nexus to destroy.
1325%
1326% o number_threads: the number of nexus threads.
1327%
1328*/
1329
1330static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1331{
1332 if (nexus_info->mapped == MagickFalse)
cristy64c3edf2012-04-13 18:50:13 +00001333 (void) RelinquishMagickMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001334 else
1335 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001336 nexus_info->cache=(Quantum *) NULL;
1337 nexus_info->pixels=(Quantum *) NULL;
1338 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001339 nexus_info->length=0;
1340 nexus_info->mapped=MagickFalse;
1341}
1342
cristya6577ff2011-09-02 19:54:26 +00001343MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001344 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001345{
cristybb503372010-05-27 20:51:26 +00001346 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001347 i;
1348
1349 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001350 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001351 {
cristy4c08aed2011-07-01 19:47:50 +00001352 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001353 RelinquishCacheNexusPixels(nexus_info[i]);
1354 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001355 }
cristye5f87c82012-02-14 12:44:17 +00001356 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001357 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001358 return(nexus_info);
1359}
1360
1361/*
1362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1363% %
1364% %
1365% %
cristy4c08aed2011-07-01 19:47:50 +00001366% G e t A u t h e n t i c M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00001367% %
1368% %
1369% %
1370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371%
cristy4c08aed2011-07-01 19:47:50 +00001372% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1373% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1374% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001375%
cristy4c08aed2011-07-01 19:47:50 +00001376% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001377%
cristy4c08aed2011-07-01 19:47:50 +00001378% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001379%
1380% A description of each parameter follows:
1381%
1382% o image: the image.
1383%
1384*/
cristy4c08aed2011-07-01 19:47:50 +00001385MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001386{
1387 CacheInfo
1388 *cache_info;
1389
cristy5c9e6f22010-09-17 17:31:01 +00001390 const int
1391 id = GetOpenMPThreadId();
1392
cristy4c08aed2011-07-01 19:47:50 +00001393 void
1394 *metacontent;
1395
cristye7cc7cf2010-09-21 13:26:47 +00001396 assert(image != (const Image *) NULL);
1397 assert(image->signature == MagickSignature);
1398 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001399 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001400 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001401 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1402 (GetAuthenticMetacontentFromHandler) NULL)
1403 {
1404 metacontent=cache_info->methods.
1405 get_authentic_metacontent_from_handler(image);
1406 return(metacontent);
1407 }
cristy6ebe97c2010-07-03 01:17:28 +00001408 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001409 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1410 cache_info->nexus_info[id]);
1411 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001412}
1413
1414/*
1415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416% %
1417% %
1418% %
cristy4c08aed2011-07-01 19:47:50 +00001419+ G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00001420% %
1421% %
1422% %
1423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1424%
cristy4c08aed2011-07-01 19:47:50 +00001425% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1426% with the last call to QueueAuthenticPixelsCache() or
1427% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001428%
cristy4c08aed2011-07-01 19:47:50 +00001429% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001430%
cristy4c08aed2011-07-01 19:47:50 +00001431% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001432%
1433% A description of each parameter follows:
1434%
1435% o image: the image.
1436%
1437*/
cristy4c08aed2011-07-01 19:47:50 +00001438static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001439{
1440 CacheInfo
1441 *cache_info;
1442
cristy2036f5c2010-09-19 21:18:17 +00001443 const int
1444 id = GetOpenMPThreadId();
1445
cristy4c08aed2011-07-01 19:47:50 +00001446 void
1447 *metacontent;
1448
cristy3ed852e2009-09-05 21:47:34 +00001449 assert(image != (const Image *) NULL);
1450 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001451 assert(image->cache != (Cache) NULL);
1452 cache_info=(CacheInfo *) image->cache;
1453 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001454 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001455 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1456 cache_info->nexus_info[id]);
1457 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001458}
1459
1460/*
1461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1462% %
1463% %
1464% %
1465+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1466% %
1467% %
1468% %
1469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1470%
1471% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1472% disk pixel cache as defined by the geometry parameters. A pointer to the
1473% pixels is returned if the pixels are transferred, otherwise a NULL is
1474% returned.
1475%
1476% The format of the GetAuthenticPixelCacheNexus() method is:
1477%
cristy4c08aed2011-07-01 19:47:50 +00001478% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001479% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001480% NexusInfo *nexus_info,ExceptionInfo *exception)
1481%
1482% A description of each parameter follows:
1483%
1484% o image: the image.
1485%
1486% o x,y,columns,rows: These values define the perimeter of a region of
1487% pixels.
1488%
1489% o nexus_info: the cache nexus to return.
1490%
1491% o exception: return any errors or warnings in this structure.
1492%
1493*/
1494
cristy7f69b802012-05-08 16:39:59 +00001495static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001496 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001497{
cristy4c08aed2011-07-01 19:47:50 +00001498 MagickBooleanType
1499 status;
1500
cristy3ed852e2009-09-05 21:47:34 +00001501 MagickOffsetType
1502 offset;
1503
cristy73724512010-04-12 14:43:14 +00001504 if (cache_info->type == PingCache)
1505 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001506 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1507 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001508 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001509 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001510 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001511}
1512
cristya6577ff2011-09-02 19:54:26 +00001513MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001514 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001515 NexusInfo *nexus_info,ExceptionInfo *exception)
1516{
1517 CacheInfo
1518 *cache_info;
1519
cristy4c08aed2011-07-01 19:47:50 +00001520 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001521 *q;
cristy3ed852e2009-09-05 21:47:34 +00001522
1523 /*
1524 Transfer pixels from the cache.
1525 */
1526 assert(image != (Image *) NULL);
1527 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001528 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1529 exception);
cristyacd2ed22011-08-30 01:44:23 +00001530 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001531 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001532 cache_info=(CacheInfo *) image->cache;
1533 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001534 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001535 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001536 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001537 return((Quantum *) NULL);
1538 if (cache_info->metacontent_extent != 0)
1539 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1540 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001541 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001542}
1543
1544/*
1545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546% %
1547% %
1548% %
1549+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1550% %
1551% %
1552% %
1553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1554%
1555% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1556% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1557%
1558% The format of the GetAuthenticPixelsFromCache() method is:
1559%
cristy4c08aed2011-07-01 19:47:50 +00001560% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001561%
1562% A description of each parameter follows:
1563%
1564% o image: the image.
1565%
1566*/
cristy4c08aed2011-07-01 19:47:50 +00001567static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001568{
1569 CacheInfo
1570 *cache_info;
1571
cristy5c9e6f22010-09-17 17:31:01 +00001572 const int
1573 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001574
cristye7cc7cf2010-09-21 13:26:47 +00001575 assert(image != (const Image *) NULL);
1576 assert(image->signature == MagickSignature);
1577 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001578 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001579 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001580 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001581 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001582}
1583
1584/*
1585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586% %
1587% %
1588% %
1589% G e t A u t h e n t i c P i x e l Q u e u e %
1590% %
1591% %
1592% %
1593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594%
cristy4c08aed2011-07-01 19:47:50 +00001595% GetAuthenticPixelQueue() returns the authentic pixels associated
1596% corresponding with the last call to QueueAuthenticPixels() or
1597% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001598%
1599% The format of the GetAuthenticPixelQueue() method is:
1600%
cristy4c08aed2011-07-01 19:47:50 +00001601% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001602%
1603% A description of each parameter follows:
1604%
1605% o image: the image.
1606%
1607*/
cristy4c08aed2011-07-01 19:47:50 +00001608MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001609{
1610 CacheInfo
1611 *cache_info;
1612
cristy2036f5c2010-09-19 21:18:17 +00001613 const int
1614 id = GetOpenMPThreadId();
1615
cristy3ed852e2009-09-05 21:47:34 +00001616 assert(image != (const Image *) NULL);
1617 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001618 assert(image->cache != (Cache) NULL);
1619 cache_info=(CacheInfo *) image->cache;
1620 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001621 if (cache_info->methods.get_authentic_pixels_from_handler !=
1622 (GetAuthenticPixelsFromHandler) NULL)
1623 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001624 assert(id < (int) cache_info->number_threads);
1625 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001626}
1627
1628/*
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630% %
1631% %
1632% %
1633% G e t A u t h e n t i c P i x e l s %
1634% %
1635% %
cristy4c08aed2011-07-01 19:47:50 +00001636% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001637%
1638% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001639% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001640% representing the region is returned, otherwise NULL is returned.
1641%
1642% The returned pointer may point to a temporary working copy of the pixels
1643% or it may point to the original pixels in memory. Performance is maximized
1644% if the selected region is part of one row, or one or more full rows, since
1645% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001646% if the image is in memory, or in a memory-mapped file. The returned pointer
1647% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001648%
1649% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001650% Quantum. If the image has corresponding metacontent,call
1651% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1652% meta-content corresponding to the region. Once the Quantum array has
1653% been updated, the changes must be saved back to the underlying image using
1654% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001655%
1656% The format of the GetAuthenticPixels() method is:
1657%
cristy4c08aed2011-07-01 19:47:50 +00001658% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001659% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001660% ExceptionInfo *exception)
1661%
1662% A description of each parameter follows:
1663%
1664% o image: the image.
1665%
1666% o x,y,columns,rows: These values define the perimeter of a region of
1667% pixels.
1668%
1669% o exception: return any errors or warnings in this structure.
1670%
1671*/
cristy4c08aed2011-07-01 19:47:50 +00001672MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001673 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001674 ExceptionInfo *exception)
1675{
1676 CacheInfo
1677 *cache_info;
1678
cristy2036f5c2010-09-19 21:18:17 +00001679 const int
1680 id = GetOpenMPThreadId();
1681
cristy4c08aed2011-07-01 19:47:50 +00001682 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001683 *q;
cristy4c08aed2011-07-01 19:47:50 +00001684
cristy3ed852e2009-09-05 21:47:34 +00001685 assert(image != (Image *) NULL);
1686 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001687 assert(image->cache != (Cache) NULL);
1688 cache_info=(CacheInfo *) image->cache;
1689 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001690 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001691 (GetAuthenticPixelsHandler) NULL)
1692 {
cristyacd2ed22011-08-30 01:44:23 +00001693 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1694 exception);
1695 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001696 }
cristy2036f5c2010-09-19 21:18:17 +00001697 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001698 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001699 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001700 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001701}
1702
1703/*
1704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1705% %
1706% %
1707% %
1708+ G e t A u t h e n t i c P i x e l s C a c h e %
1709% %
1710% %
1711% %
1712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1713%
1714% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1715% as defined by the geometry parameters. A pointer to the pixels is returned
1716% if the pixels are transferred, otherwise a NULL is returned.
1717%
1718% The format of the GetAuthenticPixelsCache() method is:
1719%
cristy4c08aed2011-07-01 19:47:50 +00001720% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001721% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001722% ExceptionInfo *exception)
1723%
1724% A description of each parameter follows:
1725%
1726% o image: the image.
1727%
1728% o x,y,columns,rows: These values define the perimeter of a region of
1729% pixels.
1730%
1731% o exception: return any errors or warnings in this structure.
1732%
1733*/
cristy4c08aed2011-07-01 19:47:50 +00001734static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001735 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001736 ExceptionInfo *exception)
1737{
1738 CacheInfo
1739 *cache_info;
1740
cristy5c9e6f22010-09-17 17:31:01 +00001741 const int
1742 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001743
cristy4c08aed2011-07-01 19:47:50 +00001744 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001745 *q;
cristy4c08aed2011-07-01 19:47:50 +00001746
cristye7cc7cf2010-09-21 13:26:47 +00001747 assert(image != (const Image *) NULL);
1748 assert(image->signature == MagickSignature);
1749 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001750 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001751 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001752 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001753 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001754 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001755 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001756 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001757 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001758}
1759
1760/*
1761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762% %
1763% %
1764% %
1765+ G e t I m a g e E x t e n t %
1766% %
1767% %
1768% %
1769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1770%
cristy4c08aed2011-07-01 19:47:50 +00001771% GetImageExtent() returns the extent of the pixels associated corresponding
1772% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001773%
1774% The format of the GetImageExtent() method is:
1775%
1776% MagickSizeType GetImageExtent(const Image *image)
1777%
1778% A description of each parameter follows:
1779%
1780% o image: the image.
1781%
1782*/
1783MagickExport MagickSizeType GetImageExtent(const Image *image)
1784{
1785 CacheInfo
1786 *cache_info;
1787
cristy5c9e6f22010-09-17 17:31:01 +00001788 const int
1789 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001790
cristy3ed852e2009-09-05 21:47:34 +00001791 assert(image != (Image *) NULL);
1792 assert(image->signature == MagickSignature);
1793 if (image->debug != MagickFalse)
1794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1795 assert(image->cache != (Cache) NULL);
1796 cache_info=(CacheInfo *) image->cache;
1797 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001798 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001799 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001800}
1801
1802/*
1803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1804% %
1805% %
1806% %
1807+ G e t I m a g e P i x e l C a c h e %
1808% %
1809% %
1810% %
1811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1812%
1813% GetImagePixelCache() ensures that there is only a single reference to the
1814% pixel cache to be modified, updating the provided cache pointer to point to
1815% a clone of the original pixel cache if necessary.
1816%
1817% The format of the GetImagePixelCache method is:
1818%
1819% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1820% ExceptionInfo *exception)
1821%
1822% A description of each parameter follows:
1823%
1824% o image: the image.
1825%
1826% o clone: any value other than MagickFalse clones the cache pixels.
1827%
1828% o exception: return any errors or warnings in this structure.
1829%
1830*/
cristyaf894d72011-08-06 23:03:10 +00001831
cristyf1832792012-05-08 18:38:18 +00001832static inline MagickBooleanType ValidatePixelCacheMorphology(
1833 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001834{
cristyf1832792012-05-08 18:38:18 +00001835 const CacheInfo
1836 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001837
cristyf1832792012-05-08 18:38:18 +00001838 const PixelChannelMap
1839 *restrict p,
1840 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001841
cristy3ed852e2009-09-05 21:47:34 +00001842 /*
1843 Does the image match the pixel cache morphology?
1844 */
1845 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001846 p=image->channel_map;
1847 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001848 if ((image->storage_class != cache_info->storage_class) ||
1849 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001850 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001851 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001852 (image->columns != cache_info->columns) ||
1853 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001854 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001855 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001856 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001857 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001858 return(MagickFalse);
1859 return(MagickTrue);
1860}
1861
cristycd01fae2011-08-06 23:52:42 +00001862static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1863 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001864{
1865 CacheInfo
1866 *cache_info;
1867
cristy3ed852e2009-09-05 21:47:34 +00001868 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001869 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001870 status;
1871
cristy50a10922010-02-15 18:35:25 +00001872 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001873 cpu_throttle = 0,
1874 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001875 time_limit = 0;
1876
cristy1ea34962010-07-01 19:49:21 +00001877 static time_t
cristy208b1002011-08-07 18:51:50 +00001878 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001879
cristyc4f9f132010-03-04 18:50:01 +00001880 status=MagickTrue;
1881 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001882 if (cpu_throttle == 0)
1883 {
1884 char
1885 *limit;
1886
1887 /*
1888 Set CPU throttle in milleseconds.
1889 */
1890 cpu_throttle=MagickResourceInfinity;
1891 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1892 if (limit == (char *) NULL)
1893 limit=GetPolicyValue("throttle");
1894 if (limit != (char *) NULL)
1895 {
1896 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1897 limit=DestroyString(limit);
1898 }
1899 }
1900 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1901 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001902 if (time_limit == 0)
1903 {
cristy6ebe97c2010-07-03 01:17:28 +00001904 /*
1905 Set the exire time in seconds.
1906 */
cristy1ea34962010-07-01 19:49:21 +00001907 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001908 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001909 }
1910 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001911 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001912 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001913 assert(image->cache != (Cache) NULL);
1914 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001915 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001916 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001917 {
cristyceb55ee2010-11-06 16:05:49 +00001918 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001919 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001920 {
cristyceb55ee2010-11-06 16:05:49 +00001921 Image
1922 clone_image;
1923
1924 CacheInfo
1925 *clone_info;
1926
1927 /*
1928 Clone pixel cache.
1929 */
1930 clone_image=(*image);
1931 clone_image.semaphore=AllocateSemaphoreInfo();
1932 clone_image.reference_count=1;
1933 clone_image.cache=ClonePixelCache(cache_info);
1934 clone_info=(CacheInfo *) clone_image.cache;
1935 status=OpenPixelCache(&clone_image,IOMode,exception);
1936 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001937 {
cristy5a7fbfb2010-11-06 16:10:59 +00001938 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001939 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001940 if (status != MagickFalse)
1941 {
cristy979bf772011-08-08 00:04:15 +00001942 if (cache_info->mode == ReadMode)
1943 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001944 destroy=MagickTrue;
1945 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001946 }
1947 }
cristyceb55ee2010-11-06 16:05:49 +00001948 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001949 }
cristyceb55ee2010-11-06 16:05:49 +00001950 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001951 }
cristy4320e0e2009-09-10 15:00:08 +00001952 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001953 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001954 if (status != MagickFalse)
1955 {
1956 /*
1957 Ensure the image matches the pixel cache morphology.
1958 */
1959 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001960 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001961 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001962 {
1963 status=OpenPixelCache(image,IOMode,exception);
1964 cache_info=(CacheInfo *) image->cache;
1965 if (cache_info->type == DiskCache)
1966 (void) ClosePixelCacheOnDisk(cache_info);
1967 }
cristy3ed852e2009-09-05 21:47:34 +00001968 }
cristyf84a1932010-01-03 18:00:18 +00001969 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001970 if (status == MagickFalse)
1971 return((Cache) NULL);
1972 return(image->cache);
1973}
1974
1975/*
1976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1977% %
1978% %
1979% %
1980% G e t O n e A u t h e n t i c P i x e l %
1981% %
1982% %
1983% %
1984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985%
1986% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1987% location. The image background color is returned if an error occurs.
1988%
1989% The format of the GetOneAuthenticPixel() method is:
1990%
cristybb503372010-05-27 20:51:26 +00001991% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00001992% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001993%
1994% A description of each parameter follows:
1995%
1996% o image: the image.
1997%
1998% o x,y: These values define the location of the pixel to return.
1999%
2000% o pixel: return a pixel at the specified (x,y) location.
2001%
2002% o exception: return any errors or warnings in this structure.
2003%
2004*/
cristyacbbb7c2010-06-30 18:56:48 +00002005MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002006 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002007{
2008 CacheInfo
2009 *cache_info;
2010
cristy4c08aed2011-07-01 19:47:50 +00002011 register Quantum
2012 *q;
cristy2036f5c2010-09-19 21:18:17 +00002013
cristy2ed42f62011-10-02 19:49:57 +00002014 register ssize_t
2015 i;
2016
cristy3ed852e2009-09-05 21:47:34 +00002017 assert(image != (Image *) NULL);
2018 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002019 assert(image->cache != (Cache) NULL);
2020 cache_info=(CacheInfo *) image->cache;
2021 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002022 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002023 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2024 (GetOneAuthenticPixelFromHandler) NULL)
2025 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2026 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002027 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2028 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002029 {
cristy9e0719b2011-12-29 03:45:45 +00002030 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2031 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2032 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2033 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2034 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002035 return(MagickFalse);
2036 }
2037 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2038 {
2039 PixelChannel
2040 channel;
2041
cristye2a912b2011-12-05 20:02:07 +00002042 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002043 pixel[channel]=q[i];
2044 }
cristy2036f5c2010-09-19 21:18:17 +00002045 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002046}
2047
2048/*
2049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2050% %
2051% %
2052% %
2053+ G e t O n e A u t h e n t i c P i x e l F r o m C a c h e %
2054% %
2055% %
2056% %
2057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2058%
2059% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2060% location. The image background color is returned if an error occurs.
2061%
2062% The format of the GetOneAuthenticPixelFromCache() method is:
2063%
2064% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002065% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002066% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002067%
2068% A description of each parameter follows:
2069%
2070% o image: the image.
2071%
2072% o x,y: These values define the location of the pixel to return.
2073%
2074% o pixel: return a pixel at the specified (x,y) location.
2075%
2076% o exception: return any errors or warnings in this structure.
2077%
2078*/
2079static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002080 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002081{
cristy098f78c2010-09-23 17:28:44 +00002082 CacheInfo
2083 *cache_info;
2084
2085 const int
2086 id = GetOpenMPThreadId();
2087
cristy4c08aed2011-07-01 19:47:50 +00002088 register Quantum
2089 *q;
cristy3ed852e2009-09-05 21:47:34 +00002090
cristy2ed42f62011-10-02 19:49:57 +00002091 register ssize_t
2092 i;
2093
cristy0158a4b2010-09-20 13:59:45 +00002094 assert(image != (const Image *) NULL);
2095 assert(image->signature == MagickSignature);
2096 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002097 cache_info=(CacheInfo *) image->cache;
2098 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002099 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002100 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002101 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2102 exception);
2103 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002104 {
cristy9e0719b2011-12-29 03:45:45 +00002105 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2106 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2107 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2108 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2109 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002110 return(MagickFalse);
2111 }
2112 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2113 {
2114 PixelChannel
2115 channel;
2116
cristye2a912b2011-12-05 20:02:07 +00002117 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002118 pixel[channel]=q[i];
2119 }
cristy3ed852e2009-09-05 21:47:34 +00002120 return(MagickTrue);
2121}
2122
2123/*
2124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2125% %
2126% %
2127% %
cristy3ed852e2009-09-05 21:47:34 +00002128% G e t O n e V i r t u a l P i x e l %
2129% %
2130% %
2131% %
2132%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2133%
2134% GetOneVirtualPixel() returns a single virtual pixel at the specified
2135% (x,y) location. The image background color is returned if an error occurs.
2136% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2137%
2138% The format of the GetOneVirtualPixel() method is:
2139%
cristybb503372010-05-27 20:51:26 +00002140% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002141% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002142%
2143% A description of each parameter follows:
2144%
2145% o image: the image.
2146%
2147% o x,y: These values define the location of the pixel to return.
2148%
2149% o pixel: return a pixel at the specified (x,y) location.
2150%
2151% o exception: return any errors or warnings in this structure.
2152%
2153*/
2154MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002155 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002156{
cristy3ed852e2009-09-05 21:47:34 +00002157 CacheInfo
2158 *cache_info;
2159
cristy0158a4b2010-09-20 13:59:45 +00002160 const int
2161 id = GetOpenMPThreadId();
2162
cristy4c08aed2011-07-01 19:47:50 +00002163 const Quantum
2164 *p;
cristy2036f5c2010-09-19 21:18:17 +00002165
cristy2ed42f62011-10-02 19:49:57 +00002166 register ssize_t
2167 i;
2168
cristy3ed852e2009-09-05 21:47:34 +00002169 assert(image != (const Image *) NULL);
2170 assert(image->signature == MagickSignature);
2171 assert(image->cache != (Cache) NULL);
2172 cache_info=(CacheInfo *) image->cache;
2173 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002174 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002175 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2176 (GetOneVirtualPixelFromHandler) NULL)
2177 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2178 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002179 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002180 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002181 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002182 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002183 {
cristy9e0719b2011-12-29 03:45:45 +00002184 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2185 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2186 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2187 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2188 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002189 return(MagickFalse);
2190 }
2191 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2192 {
2193 PixelChannel
2194 channel;
2195
cristye2a912b2011-12-05 20:02:07 +00002196 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002197 pixel[channel]=p[i];
2198 }
cristy2036f5c2010-09-19 21:18:17 +00002199 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002200}
2201
2202/*
2203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204% %
2205% %
2206% %
2207+ G e t O n e V i r t u a l P i x e l F r o m C a c h e %
2208% %
2209% %
2210% %
2211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212%
2213% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2214% specified (x,y) location. The image background color is returned if an
2215% error occurs.
2216%
2217% The format of the GetOneVirtualPixelFromCache() method is:
2218%
2219% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002220% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002221% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002222%
2223% A description of each parameter follows:
2224%
2225% o image: the image.
2226%
2227% o virtual_pixel_method: the virtual pixel method.
2228%
2229% o x,y: These values define the location of the pixel to return.
2230%
2231% o pixel: return a pixel at the specified (x,y) location.
2232%
2233% o exception: return any errors or warnings in this structure.
2234%
2235*/
2236static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002237 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002238 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002239{
cristy0158a4b2010-09-20 13:59:45 +00002240 CacheInfo
2241 *cache_info;
2242
2243 const int
2244 id = GetOpenMPThreadId();
2245
cristy4c08aed2011-07-01 19:47:50 +00002246 const Quantum
2247 *p;
cristy3ed852e2009-09-05 21:47:34 +00002248
cristy2ed42f62011-10-02 19:49:57 +00002249 register ssize_t
2250 i;
2251
cristye7cc7cf2010-09-21 13:26:47 +00002252 assert(image != (const Image *) NULL);
2253 assert(image->signature == MagickSignature);
2254 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002255 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002256 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002257 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002258 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002259 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002260 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002261 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002262 {
cristy9e0719b2011-12-29 03:45:45 +00002263 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2264 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2265 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2266 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2267 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002268 return(MagickFalse);
2269 }
2270 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2271 {
2272 PixelChannel
2273 channel;
2274
cristye2a912b2011-12-05 20:02:07 +00002275 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002276 pixel[channel]=p[i];
2277 }
cristy3ed852e2009-09-05 21:47:34 +00002278 return(MagickTrue);
2279}
2280
2281/*
2282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2283% %
2284% %
2285% %
cristy3aa93752011-12-18 15:54:24 +00002286% G e t O n e V i r t u a l P i x e l I n f o %
2287% %
2288% %
2289% %
2290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2291%
2292% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2293% location. The image background color is returned if an error occurs. If
2294% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2295%
2296% The format of the GetOneVirtualPixelInfo() method is:
2297%
2298% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2299% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2300% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2301%
2302% A description of each parameter follows:
2303%
2304% o image: the image.
2305%
2306% o virtual_pixel_method: the virtual pixel method.
2307%
2308% o x,y: these values define the location of the pixel to return.
2309%
2310% o pixel: return a pixel at the specified (x,y) location.
2311%
2312% o exception: return any errors or warnings in this structure.
2313%
2314*/
2315MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2316 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2317 PixelInfo *pixel,ExceptionInfo *exception)
2318{
2319 CacheInfo
2320 *cache_info;
2321
2322 const int
2323 id = GetOpenMPThreadId();
2324
2325 register const Quantum
2326 *p;
2327
2328 assert(image != (const Image *) NULL);
2329 assert(image->signature == MagickSignature);
2330 assert(image->cache != (Cache) NULL);
2331 cache_info=(CacheInfo *) image->cache;
2332 assert(cache_info->signature == MagickSignature);
2333 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002334 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002335 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2336 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002337 if (p == (const Quantum *) NULL)
2338 return(MagickFalse);
2339 GetPixelInfoPixel(image,p,pixel);
2340 return(MagickTrue);
2341}
2342
2343/*
2344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2345% %
2346% %
2347% %
cristy3ed852e2009-09-05 21:47:34 +00002348+ G e t P i x e l C a c h e C o l o r s p a c e %
2349% %
2350% %
2351% %
2352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2353%
2354% GetPixelCacheColorspace() returns the class type of the pixel cache.
2355%
2356% The format of the GetPixelCacheColorspace() method is:
2357%
2358% Colorspace GetPixelCacheColorspace(Cache cache)
2359%
2360% A description of each parameter follows:
2361%
2362% o cache: the pixel cache.
2363%
2364*/
cristya6577ff2011-09-02 19:54:26 +00002365MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002366{
2367 CacheInfo
2368 *cache_info;
2369
2370 assert(cache != (Cache) NULL);
2371 cache_info=(CacheInfo *) cache;
2372 assert(cache_info->signature == MagickSignature);
2373 if (cache_info->debug != MagickFalse)
2374 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2375 cache_info->filename);
2376 return(cache_info->colorspace);
2377}
2378
2379/*
2380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2381% %
2382% %
2383% %
2384+ G e t P i x e l C a c h e M e t h o d s %
2385% %
2386% %
2387% %
2388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2389%
2390% GetPixelCacheMethods() initializes the CacheMethods structure.
2391%
2392% The format of the GetPixelCacheMethods() method is:
2393%
2394% void GetPixelCacheMethods(CacheMethods *cache_methods)
2395%
2396% A description of each parameter follows:
2397%
2398% o cache_methods: Specifies a pointer to a CacheMethods structure.
2399%
2400*/
cristya6577ff2011-09-02 19:54:26 +00002401MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002402{
2403 assert(cache_methods != (CacheMethods *) NULL);
2404 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2405 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2406 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002407 cache_methods->get_virtual_metacontent_from_handler=
2408 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002409 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2410 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002411 cache_methods->get_authentic_metacontent_from_handler=
2412 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002413 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2414 cache_methods->get_one_authentic_pixel_from_handler=
2415 GetOneAuthenticPixelFromCache;
2416 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2417 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2418 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2419}
2420
2421/*
2422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2423% %
2424% %
2425% %
2426+ G e t P i x e l C a c h e N e x u s E x t e n t %
2427% %
2428% %
2429% %
2430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2431%
cristy4c08aed2011-07-01 19:47:50 +00002432% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2433% corresponding with the last call to SetPixelCacheNexusPixels() or
2434% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002435%
2436% The format of the GetPixelCacheNexusExtent() method is:
2437%
2438% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2439% NexusInfo *nexus_info)
2440%
2441% A description of each parameter follows:
2442%
2443% o nexus_info: the nexus info.
2444%
2445*/
cristya6577ff2011-09-02 19:54:26 +00002446MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002447 NexusInfo *nexus_info)
2448{
2449 CacheInfo
2450 *cache_info;
2451
2452 MagickSizeType
2453 extent;
2454
cristy9f027d12011-09-21 01:17:17 +00002455 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002456 cache_info=(CacheInfo *) cache;
2457 assert(cache_info->signature == MagickSignature);
2458 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2459 if (extent == 0)
2460 return((MagickSizeType) cache_info->columns*cache_info->rows);
2461 return(extent);
2462}
2463
2464/*
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466% %
2467% %
2468% %
cristy4c08aed2011-07-01 19:47:50 +00002469+ G e t P i x e l C a c h e N e x u s M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002470% %
2471% %
2472% %
2473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474%
cristy4c08aed2011-07-01 19:47:50 +00002475% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2476% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002477%
cristy4c08aed2011-07-01 19:47:50 +00002478% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002479%
cristy4c08aed2011-07-01 19:47:50 +00002480% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002481% NexusInfo *nexus_info)
2482%
2483% A description of each parameter follows:
2484%
2485% o cache: the pixel cache.
2486%
cristy4c08aed2011-07-01 19:47:50 +00002487% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002488%
2489*/
cristya6577ff2011-09-02 19:54:26 +00002490MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002491 NexusInfo *nexus_info)
2492{
2493 CacheInfo
2494 *cache_info;
2495
cristy9f027d12011-09-21 01:17:17 +00002496 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002497 cache_info=(CacheInfo *) cache;
2498 assert(cache_info->signature == MagickSignature);
2499 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002500 return((void *) NULL);
2501 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002502}
2503
2504/*
2505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2506% %
2507% %
2508% %
2509+ G e t P i x e l C a c h e N e x u s P i x e l s %
2510% %
2511% %
2512% %
2513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2514%
2515% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2516% cache nexus.
2517%
2518% The format of the GetPixelCacheNexusPixels() method is:
2519%
cristy4c08aed2011-07-01 19:47:50 +00002520% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002521% NexusInfo *nexus_info)
2522%
2523% A description of each parameter follows:
2524%
2525% o cache: the pixel cache.
2526%
2527% o nexus_info: the cache nexus to return the pixels.
2528%
2529*/
cristya6577ff2011-09-02 19:54:26 +00002530MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002531 NexusInfo *nexus_info)
2532{
2533 CacheInfo
2534 *cache_info;
2535
cristy9f027d12011-09-21 01:17:17 +00002536 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002537 cache_info=(CacheInfo *) cache;
2538 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002539 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002540 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002541 return(nexus_info->pixels);
2542}
2543
2544/*
2545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2546% %
2547% %
2548% %
cristy056ba772010-01-02 23:33:54 +00002549+ G e t P i x e l C a c h e P i x e l s %
2550% %
2551% %
2552% %
2553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2554%
2555% GetPixelCachePixels() returns the pixels associated with the specified image.
2556%
2557% The format of the GetPixelCachePixels() method is:
2558%
cristyf84a1932010-01-03 18:00:18 +00002559% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2560% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002561%
2562% A description of each parameter follows:
2563%
2564% o image: the image.
2565%
2566% o length: the pixel cache length.
2567%
cristyf84a1932010-01-03 18:00:18 +00002568% o exception: return any errors or warnings in this structure.
2569%
cristy056ba772010-01-02 23:33:54 +00002570*/
cristyd1dd6e42011-09-04 01:46:08 +00002571MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002572 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002573{
2574 CacheInfo
2575 *cache_info;
2576
2577 assert(image != (const Image *) NULL);
2578 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002579 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002580 assert(length != (MagickSizeType *) NULL);
2581 assert(exception != (ExceptionInfo *) NULL);
2582 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002583 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002584 assert(cache_info->signature == MagickSignature);
2585 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002586 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002587 return((void *) NULL);
2588 *length=cache_info->length;
2589 return((void *) cache_info->pixels);
2590}
2591
2592/*
2593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2594% %
2595% %
2596% %
cristyb32b90a2009-09-07 21:45:48 +00002597+ G e t P i x e l C a c h e S t o r a g e C l a s s %
cristy3ed852e2009-09-05 21:47:34 +00002598% %
2599% %
2600% %
2601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2602%
2603% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2604%
2605% The format of the GetPixelCacheStorageClass() method is:
2606%
2607% ClassType GetPixelCacheStorageClass(Cache cache)
2608%
2609% A description of each parameter follows:
2610%
2611% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2612%
2613% o cache: the pixel cache.
2614%
2615*/
cristya6577ff2011-09-02 19:54:26 +00002616MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002617{
2618 CacheInfo
2619 *cache_info;
2620
2621 assert(cache != (Cache) NULL);
2622 cache_info=(CacheInfo *) cache;
2623 assert(cache_info->signature == MagickSignature);
2624 if (cache_info->debug != MagickFalse)
2625 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2626 cache_info->filename);
2627 return(cache_info->storage_class);
2628}
2629
2630/*
2631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2632% %
2633% %
2634% %
cristyb32b90a2009-09-07 21:45:48 +00002635+ G e t P i x e l C a c h e T i l e S i z e %
2636% %
2637% %
2638% %
2639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2640%
2641% GetPixelCacheTileSize() returns the pixel cache tile size.
2642%
2643% The format of the GetPixelCacheTileSize() method is:
2644%
cristybb503372010-05-27 20:51:26 +00002645% void GetPixelCacheTileSize(const Image *image,size_t *width,
2646% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002647%
2648% A description of each parameter follows:
2649%
2650% o image: the image.
2651%
2652% o width: the optimize cache tile width in pixels.
2653%
2654% o height: the optimize cache tile height in pixels.
2655%
2656*/
cristya6577ff2011-09-02 19:54:26 +00002657MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002658 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002659{
cristy4c08aed2011-07-01 19:47:50 +00002660 CacheInfo
2661 *cache_info;
2662
cristyb32b90a2009-09-07 21:45:48 +00002663 assert(image != (Image *) NULL);
2664 assert(image->signature == MagickSignature);
2665 if (image->debug != MagickFalse)
2666 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002667 cache_info=(CacheInfo *) image->cache;
2668 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002669 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002670 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002671 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002672 *height=(*width);
2673}
2674
2675/*
2676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2677% %
2678% %
2679% %
2680+ G e t P i x e l C a c h e T y p e %
2681% %
2682% %
2683% %
2684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2685%
2686% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2687%
2688% The format of the GetPixelCacheType() method is:
2689%
2690% CacheType GetPixelCacheType(const Image *image)
2691%
2692% A description of each parameter follows:
2693%
2694% o image: the image.
2695%
2696*/
cristya6577ff2011-09-02 19:54:26 +00002697MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002698{
2699 CacheInfo
2700 *cache_info;
2701
2702 assert(image != (Image *) NULL);
2703 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002704 assert(image->cache != (Cache) NULL);
2705 cache_info=(CacheInfo *) image->cache;
2706 assert(cache_info->signature == MagickSignature);
2707 return(cache_info->type);
2708}
2709
2710/*
2711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2712% %
2713% %
2714% %
cristy3ed852e2009-09-05 21:47:34 +00002715+ G e t P i x e l C a c h e V i r t u a l M e t h o d %
2716% %
2717% %
2718% %
2719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2720%
2721% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2722% pixel cache. A virtual pixel is any pixel access that is outside the
2723% boundaries of the image cache.
2724%
2725% The format of the GetPixelCacheVirtualMethod() method is:
2726%
2727% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2728%
2729% A description of each parameter follows:
2730%
2731% o image: the image.
2732%
2733*/
cristyd1dd6e42011-09-04 01:46:08 +00002734MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002735{
2736 CacheInfo
2737 *cache_info;
2738
2739 assert(image != (Image *) NULL);
2740 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002741 assert(image->cache != (Cache) NULL);
2742 cache_info=(CacheInfo *) image->cache;
2743 assert(cache_info->signature == MagickSignature);
2744 return(cache_info->virtual_pixel_method);
2745}
2746
2747/*
2748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749% %
2750% %
2751% %
cristy4c08aed2011-07-01 19:47:50 +00002752+ G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00002753% %
2754% %
2755% %
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757%
cristy4c08aed2011-07-01 19:47:50 +00002758% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2759% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002760%
cristy4c08aed2011-07-01 19:47:50 +00002761% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002762%
cristy4c08aed2011-07-01 19:47:50 +00002763% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002764%
2765% A description of each parameter follows:
2766%
2767% o image: the image.
2768%
2769*/
cristy4c08aed2011-07-01 19:47:50 +00002770static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002771{
2772 CacheInfo
2773 *cache_info;
2774
cristy5c9e6f22010-09-17 17:31:01 +00002775 const int
2776 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002777
cristy4c08aed2011-07-01 19:47:50 +00002778 const void
2779 *metacontent;
2780
cristye7cc7cf2010-09-21 13:26:47 +00002781 assert(image != (const Image *) NULL);
2782 assert(image->signature == MagickSignature);
2783 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002784 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002785 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002786 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002787 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2788 cache_info->nexus_info[id]);
2789 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002790}
2791
2792/*
2793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2794% %
2795% %
2796% %
cristy4c08aed2011-07-01 19:47:50 +00002797+ G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00002798% %
2799% %
2800% %
2801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802%
cristy4c08aed2011-07-01 19:47:50 +00002803% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2804% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002805%
cristy4c08aed2011-07-01 19:47:50 +00002806% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002807%
cristy4c08aed2011-07-01 19:47:50 +00002808% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002809% NexusInfo *nexus_info)
2810%
2811% A description of each parameter follows:
2812%
2813% o cache: the pixel cache.
2814%
cristy4c08aed2011-07-01 19:47:50 +00002815% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002816%
2817*/
cristya6577ff2011-09-02 19:54:26 +00002818MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002819 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002820{
2821 CacheInfo
2822 *cache_info;
2823
cristye7cc7cf2010-09-21 13:26:47 +00002824 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002825 cache_info=(CacheInfo *) cache;
2826 assert(cache_info->signature == MagickSignature);
2827 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002828 return((void *) NULL);
2829 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002830}
2831
2832/*
2833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2834% %
2835% %
2836% %
cristy4c08aed2011-07-01 19:47:50 +00002837% G e t V i r t u a l M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002838% %
2839% %
2840% %
2841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2842%
cristy4c08aed2011-07-01 19:47:50 +00002843% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2844% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2845% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002846%
cristy4c08aed2011-07-01 19:47:50 +00002847% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002848%
cristy4c08aed2011-07-01 19:47:50 +00002849% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002850%
2851% A description of each parameter follows:
2852%
2853% o image: the image.
2854%
2855*/
cristy4c08aed2011-07-01 19:47:50 +00002856MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002857{
2858 CacheInfo
2859 *cache_info;
2860
cristy2036f5c2010-09-19 21:18:17 +00002861 const int
2862 id = GetOpenMPThreadId();
2863
cristy4c08aed2011-07-01 19:47:50 +00002864 const void
2865 *metacontent;
2866
cristy3ed852e2009-09-05 21:47:34 +00002867 assert(image != (const Image *) NULL);
2868 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002869 assert(image->cache != (Cache) NULL);
2870 cache_info=(CacheInfo *) image->cache;
2871 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002872 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002873 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002874 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002875 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002876 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2877 cache_info->nexus_info[id]);
2878 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002879}
2880
2881/*
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883% %
2884% %
2885% %
2886+ G e t V i r t u a l P i x e l s F r o m N e x u s %
2887% %
2888% %
2889% %
2890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891%
2892% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2893% pixel cache as defined by the geometry parameters. A pointer to the pixels
2894% is returned if the pixels are transferred, otherwise a NULL is returned.
2895%
2896% The format of the GetVirtualPixelsFromNexus() method is:
2897%
cristy4c08aed2011-07-01 19:47:50 +00002898% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002899% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002900% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2901% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002902%
2903% A description of each parameter follows:
2904%
2905% o image: the image.
2906%
2907% o virtual_pixel_method: the virtual pixel method.
2908%
2909% o x,y,columns,rows: These values define the perimeter of a region of
2910% pixels.
2911%
2912% o nexus_info: the cache nexus to acquire.
2913%
2914% o exception: return any errors or warnings in this structure.
2915%
2916*/
2917
cristybb503372010-05-27 20:51:26 +00002918static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002919 DitherMatrix[64] =
2920 {
2921 0, 48, 12, 60, 3, 51, 15, 63,
2922 32, 16, 44, 28, 35, 19, 47, 31,
2923 8, 56, 4, 52, 11, 59, 7, 55,
2924 40, 24, 36, 20, 43, 27, 39, 23,
2925 2, 50, 14, 62, 1, 49, 13, 61,
2926 34, 18, 46, 30, 33, 17, 45, 29,
2927 10, 58, 6, 54, 9, 57, 5, 53,
2928 42, 26, 38, 22, 41, 25, 37, 21
2929 };
2930
cristybb503372010-05-27 20:51:26 +00002931static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002932{
cristybb503372010-05-27 20:51:26 +00002933 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002934 index;
2935
2936 index=x+DitherMatrix[x & 0x07]-32L;
2937 if (index < 0L)
2938 return(0L);
cristybb503372010-05-27 20:51:26 +00002939 if (index >= (ssize_t) columns)
2940 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002941 return(index);
2942}
2943
cristybb503372010-05-27 20:51:26 +00002944static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002945{
cristybb503372010-05-27 20:51:26 +00002946 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002947 index;
2948
2949 index=y+DitherMatrix[y & 0x07]-32L;
2950 if (index < 0L)
2951 return(0L);
cristybb503372010-05-27 20:51:26 +00002952 if (index >= (ssize_t) rows)
2953 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002954 return(index);
2955}
2956
cristybb503372010-05-27 20:51:26 +00002957static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002958{
2959 if (x < 0L)
2960 return(0L);
cristybb503372010-05-27 20:51:26 +00002961 if (x >= (ssize_t) columns)
2962 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002963 return(x);
2964}
2965
cristybb503372010-05-27 20:51:26 +00002966static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002967{
2968 if (y < 0L)
2969 return(0L);
cristybb503372010-05-27 20:51:26 +00002970 if (y >= (ssize_t) rows)
2971 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002972 return(y);
2973}
2974
cristybb503372010-05-27 20:51:26 +00002975static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002976{
cristybb503372010-05-27 20:51:26 +00002977 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002978}
2979
cristybb503372010-05-27 20:51:26 +00002980static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002981{
cristybb503372010-05-27 20:51:26 +00002982 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002983}
2984
cristybb503372010-05-27 20:51:26 +00002985static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2986 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002987{
2988 MagickModulo
2989 modulo;
2990
cristy6162bb42011-07-18 11:34:09 +00002991 /*
2992 Compute the remainder of dividing offset by extent. It returns not only
2993 the quotient (tile the offset falls in) but also the positive remainer
2994 within that tile such that 0 <= remainder < extent. This method is
2995 essentially a ldiv() using a floored modulo division rather than the
2996 normal default truncated modulo division.
2997 */
cristybb503372010-05-27 20:51:26 +00002998 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002999 if (offset < 0L)
3000 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003001 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003002 return(modulo);
3003}
3004
cristya6577ff2011-09-02 19:54:26 +00003005MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003006 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3007 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003008 ExceptionInfo *exception)
3009{
3010 CacheInfo
3011 *cache_info;
3012
3013 MagickOffsetType
3014 offset;
3015
3016 MagickSizeType
3017 length,
3018 number_pixels;
3019
3020 NexusInfo
3021 **virtual_nexus;
3022
cristy4c08aed2011-07-01 19:47:50 +00003023 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003024 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003025 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003026
3027 RectangleInfo
3028 region;
3029
cristy4c08aed2011-07-01 19:47:50 +00003030 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003031 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003032
cristy4c08aed2011-07-01 19:47:50 +00003033 register const void
3034 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003035
cristy4c08aed2011-07-01 19:47:50 +00003036 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003037 *restrict q;
3038
cristybb503372010-05-27 20:51:26 +00003039 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003040 i,
3041 u;
cristy3ed852e2009-09-05 21:47:34 +00003042
cristy4c08aed2011-07-01 19:47:50 +00003043 register unsigned char
3044 *restrict s;
3045
cristy105ba3c2011-07-18 02:28:38 +00003046 ssize_t
3047 v;
3048
cristy4c08aed2011-07-01 19:47:50 +00003049 void
cristy105ba3c2011-07-18 02:28:38 +00003050 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003051
cristy3ed852e2009-09-05 21:47:34 +00003052 /*
3053 Acquire pixels.
3054 */
cristye7cc7cf2010-09-21 13:26:47 +00003055 assert(image != (const Image *) NULL);
3056 assert(image->signature == MagickSignature);
3057 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003058 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003059 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003060 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003061 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003062 region.x=x;
3063 region.y=y;
3064 region.width=columns;
3065 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003066 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003067 if (pixels == (Quantum *) NULL)
3068 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003069 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003070 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3071 nexus_info->region.x;
3072 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3073 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003074 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3075 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003076 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3077 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003078 {
3079 MagickBooleanType
3080 status;
3081
3082 /*
3083 Pixel request is inside cache extents.
3084 */
cristy4c08aed2011-07-01 19:47:50 +00003085 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003086 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003087 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3088 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003089 return((const Quantum *) NULL);
3090 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003091 {
cristy4c08aed2011-07-01 19:47:50 +00003092 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003093 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003094 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003095 }
cristyacd2ed22011-08-30 01:44:23 +00003096 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003097 }
3098 /*
3099 Pixel request is outside cache extents.
3100 */
cristy4c08aed2011-07-01 19:47:50 +00003101 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003102 virtual_nexus=AcquirePixelCacheNexus(1);
3103 if (virtual_nexus == (NexusInfo **) NULL)
3104 {
cristy4c08aed2011-07-01 19:47:50 +00003105 if (virtual_nexus != (NexusInfo **) NULL)
3106 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003107 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003108 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003109 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003110 }
cristy105ba3c2011-07-18 02:28:38 +00003111 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3112 sizeof(*virtual_pixel));
3113 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003114 switch (virtual_pixel_method)
3115 {
cristy4c08aed2011-07-01 19:47:50 +00003116 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003117 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003118 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003119 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 case MaskVirtualPixelMethod:
3121 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003122 case EdgeVirtualPixelMethod:
3123 case CheckerTileVirtualPixelMethod:
3124 case HorizontalTileVirtualPixelMethod:
3125 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003126 {
cristy4c08aed2011-07-01 19:47:50 +00003127 if (cache_info->metacontent_extent != 0)
3128 {
cristy6162bb42011-07-18 11:34:09 +00003129 /*
3130 Acquire a metacontent buffer.
3131 */
cristya64b85d2011-09-14 01:02:31 +00003132 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003133 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003134 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003135 {
cristy4c08aed2011-07-01 19:47:50 +00003136 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3137 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003138 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003139 return((const Quantum *) NULL);
3140 }
cristy105ba3c2011-07-18 02:28:38 +00003141 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003142 cache_info->metacontent_extent);
3143 }
3144 switch (virtual_pixel_method)
3145 {
3146 case BlackVirtualPixelMethod:
3147 {
cristy30301712011-07-18 15:06:51 +00003148 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3149 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003150 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3151 break;
3152 }
3153 case GrayVirtualPixelMethod:
3154 {
cristy30301712011-07-18 15:06:51 +00003155 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003156 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3157 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003158 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3159 break;
3160 }
3161 case TransparentVirtualPixelMethod:
3162 {
cristy30301712011-07-18 15:06:51 +00003163 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3164 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003165 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3166 break;
3167 }
3168 case MaskVirtualPixelMethod:
3169 case WhiteVirtualPixelMethod:
3170 {
cristy30301712011-07-18 15:06:51 +00003171 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3172 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003173 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3174 break;
3175 }
3176 default:
3177 {
cristy9e0719b2011-12-29 03:45:45 +00003178 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3179 virtual_pixel);
3180 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3181 virtual_pixel);
3182 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3183 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003184 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3185 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003186 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3187 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003188 break;
3189 }
3190 }
cristy3ed852e2009-09-05 21:47:34 +00003191 break;
3192 }
3193 default:
cristy3ed852e2009-09-05 21:47:34 +00003194 break;
cristy3ed852e2009-09-05 21:47:34 +00003195 }
cristybb503372010-05-27 20:51:26 +00003196 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003197 {
cristybb503372010-05-27 20:51:26 +00003198 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003199 {
3200 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003201 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003202 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3203 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003204 {
3205 MagickModulo
3206 x_modulo,
3207 y_modulo;
3208
3209 /*
3210 Transfer a single pixel.
3211 */
3212 length=(MagickSizeType) 1;
3213 switch (virtual_pixel_method)
3214 {
cristy3ed852e2009-09-05 21:47:34 +00003215 default:
3216 {
3217 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003218 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003219 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003220 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003221 break;
3222 }
3223 case RandomVirtualPixelMethod:
3224 {
3225 if (cache_info->random_info == (RandomInfo *) NULL)
3226 cache_info->random_info=AcquireRandomInfo();
3227 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003228 RandomX(cache_info->random_info,cache_info->columns),
3229 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003230 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003231 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003232 break;
3233 }
3234 case DitherVirtualPixelMethod:
3235 {
3236 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003237 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003238 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003239 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003240 break;
3241 }
3242 case TileVirtualPixelMethod:
3243 {
3244 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3245 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3246 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003247 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003248 exception);
cristy4c08aed2011-07-01 19:47:50 +00003249 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003250 break;
3251 }
3252 case MirrorVirtualPixelMethod:
3253 {
3254 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3255 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003256 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003257 x_modulo.remainder-1L;
3258 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3259 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003260 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003261 y_modulo.remainder-1L;
3262 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003263 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003264 exception);
cristy4c08aed2011-07-01 19:47:50 +00003265 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003266 break;
3267 }
3268 case HorizontalTileEdgeVirtualPixelMethod:
3269 {
3270 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3271 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003272 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003273 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003274 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003275 break;
3276 }
3277 case VerticalTileEdgeVirtualPixelMethod:
3278 {
3279 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3280 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003281 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003282 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003283 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3284 break;
3285 }
3286 case BackgroundVirtualPixelMethod:
3287 case BlackVirtualPixelMethod:
3288 case GrayVirtualPixelMethod:
3289 case TransparentVirtualPixelMethod:
3290 case MaskVirtualPixelMethod:
3291 case WhiteVirtualPixelMethod:
3292 {
3293 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003294 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003295 break;
3296 }
3297 case EdgeVirtualPixelMethod:
3298 case CheckerTileVirtualPixelMethod:
3299 {
3300 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3301 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3302 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3303 {
3304 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003305 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003306 break;
3307 }
3308 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3309 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3310 exception);
3311 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3312 break;
3313 }
3314 case HorizontalTileVirtualPixelMethod:
3315 {
3316 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3317 {
3318 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003319 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003320 break;
3321 }
3322 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3323 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3324 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3325 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3326 exception);
3327 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3328 break;
3329 }
3330 case VerticalTileVirtualPixelMethod:
3331 {
3332 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3333 {
3334 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003335 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003336 break;
3337 }
3338 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3339 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3340 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3341 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3342 exception);
3343 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003344 break;
3345 }
3346 }
cristy4c08aed2011-07-01 19:47:50 +00003347 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003348 break;
cristyed231572011-07-14 02:18:59 +00003349 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003350 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003351 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003352 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003353 {
3354 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3355 s+=cache_info->metacontent_extent;
3356 }
cristy3ed852e2009-09-05 21:47:34 +00003357 continue;
3358 }
3359 /*
3360 Transfer a run of pixels.
3361 */
cristy4c08aed2011-07-01 19:47:50 +00003362 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3363 length,1UL,*virtual_nexus,exception);
3364 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003365 break;
cristy4c08aed2011-07-01 19:47:50 +00003366 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003367 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3368 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003369 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003370 {
cristy4c08aed2011-07-01 19:47:50 +00003371 (void) memcpy(s,r,(size_t) length);
3372 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003373 }
3374 }
3375 }
cristy4c08aed2011-07-01 19:47:50 +00003376 /*
3377 Free resources.
3378 */
cristy105ba3c2011-07-18 02:28:38 +00003379 if (virtual_metacontent != (void *) NULL)
3380 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003381 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3382 return(pixels);
3383}
3384
3385/*
3386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3387% %
3388% %
3389% %
3390+ G e t V i r t u a l P i x e l C a c h e %
3391% %
3392% %
3393% %
3394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3395%
3396% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3397% cache as defined by the geometry parameters. A pointer to the pixels
3398% is returned if the pixels are transferred, otherwise a NULL is returned.
3399%
3400% The format of the GetVirtualPixelCache() method is:
3401%
cristy4c08aed2011-07-01 19:47:50 +00003402% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003403% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3404% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003405% ExceptionInfo *exception)
3406%
3407% A description of each parameter follows:
3408%
3409% o image: the image.
3410%
3411% o virtual_pixel_method: the virtual pixel method.
3412%
3413% o x,y,columns,rows: These values define the perimeter of a region of
3414% pixels.
3415%
3416% o exception: return any errors or warnings in this structure.
3417%
3418*/
cristy4c08aed2011-07-01 19:47:50 +00003419static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003420 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3421 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003422{
3423 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003424 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003425
cristy5c9e6f22010-09-17 17:31:01 +00003426 const int
3427 id = GetOpenMPThreadId();
3428
cristy4c08aed2011-07-01 19:47:50 +00003429 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003430 *p;
cristy4c08aed2011-07-01 19:47:50 +00003431
cristye7cc7cf2010-09-21 13:26:47 +00003432 assert(image != (const Image *) NULL);
3433 assert(image->signature == MagickSignature);
3434 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003435 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003436 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003437 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003439 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003440 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003441}
3442
3443/*
3444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3445% %
3446% %
3447% %
3448% G e t V i r t u a l P i x e l Q u e u e %
3449% %
3450% %
3451% %
3452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3453%
cristy4c08aed2011-07-01 19:47:50 +00003454% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3455% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003456%
3457% The format of the GetVirtualPixelQueue() method is:
3458%
cristy4c08aed2011-07-01 19:47:50 +00003459% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003460%
3461% A description of each parameter follows:
3462%
3463% o image: the image.
3464%
3465*/
cristy4c08aed2011-07-01 19:47:50 +00003466MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003467{
3468 CacheInfo
3469 *cache_info;
3470
cristy2036f5c2010-09-19 21:18:17 +00003471 const int
3472 id = GetOpenMPThreadId();
3473
cristy3ed852e2009-09-05 21:47:34 +00003474 assert(image != (const Image *) NULL);
3475 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003476 assert(image->cache != (Cache) NULL);
3477 cache_info=(CacheInfo *) image->cache;
3478 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003479 if (cache_info->methods.get_virtual_pixels_handler !=
3480 (GetVirtualPixelsHandler) NULL)
3481 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003482 assert(id < (int) cache_info->number_threads);
3483 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003484}
3485
3486/*
3487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3488% %
3489% %
3490% %
3491% G e t V i r t u a l P i x e l s %
3492% %
3493% %
3494% %
3495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3496%
3497% GetVirtualPixels() returns an immutable pixel region. If the
3498% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003499% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003500% copy of the pixels or it may point to the original pixels in memory.
3501% Performance is maximized if the selected region is part of one row, or one
3502% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003503% (without a copy) if the image is in memory, or in a memory-mapped file. The
3504% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003505%
3506% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003507% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3508% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3509% access the meta-content (of type void) corresponding to the the
3510% region.
cristy3ed852e2009-09-05 21:47:34 +00003511%
3512% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3513%
3514% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3515% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3516% GetCacheViewAuthenticPixels() instead.
3517%
3518% The format of the GetVirtualPixels() method is:
3519%
cristy4c08aed2011-07-01 19:47:50 +00003520% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003521% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003522% ExceptionInfo *exception)
3523%
3524% A description of each parameter follows:
3525%
3526% o image: the image.
3527%
3528% o x,y,columns,rows: These values define the perimeter of a region of
3529% pixels.
3530%
3531% o exception: return any errors or warnings in this structure.
3532%
3533*/
cristy4c08aed2011-07-01 19:47:50 +00003534MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003535 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3536 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003537{
3538 CacheInfo
3539 *cache_info;
3540
cristy2036f5c2010-09-19 21:18:17 +00003541 const int
3542 id = GetOpenMPThreadId();
3543
cristy4c08aed2011-07-01 19:47:50 +00003544 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003545 *p;
cristy4c08aed2011-07-01 19:47:50 +00003546
cristy3ed852e2009-09-05 21:47:34 +00003547 assert(image != (const Image *) NULL);
3548 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003549 assert(image->cache != (Cache) NULL);
3550 cache_info=(CacheInfo *) image->cache;
3551 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003552 if (cache_info->methods.get_virtual_pixel_handler !=
3553 (GetVirtualPixelHandler) NULL)
3554 return(cache_info->methods.get_virtual_pixel_handler(image,
3555 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003556 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003557 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003558 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003559 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003560}
3561
3562/*
3563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3564% %
3565% %
3566% %
3567+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3568% %
3569% %
3570% %
3571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3572%
cristy4c08aed2011-07-01 19:47:50 +00003573% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3574% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003575%
3576% The format of the GetVirtualPixelsCache() method is:
3577%
cristy4c08aed2011-07-01 19:47:50 +00003578% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003579%
3580% A description of each parameter follows:
3581%
3582% o image: the image.
3583%
3584*/
cristy4c08aed2011-07-01 19:47:50 +00003585static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003586{
3587 CacheInfo
3588 *cache_info;
3589
cristy5c9e6f22010-09-17 17:31:01 +00003590 const int
3591 id = GetOpenMPThreadId();
3592
cristye7cc7cf2010-09-21 13:26:47 +00003593 assert(image != (const Image *) NULL);
3594 assert(image->signature == MagickSignature);
3595 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003596 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003597 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003598 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003599 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003600}
3601
3602/*
3603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604% %
3605% %
3606% %
3607+ G e t V i r t u a l P i x e l s N e x u s %
3608% %
3609% %
3610% %
3611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3612%
3613% GetVirtualPixelsNexus() returns the pixels associated with the specified
3614% cache nexus.
3615%
3616% The format of the GetVirtualPixelsNexus() method is:
3617%
cristy4c08aed2011-07-01 19:47:50 +00003618% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003619% NexusInfo *nexus_info)
3620%
3621% A description of each parameter follows:
3622%
3623% o cache: the pixel cache.
3624%
3625% o nexus_info: the cache nexus to return the colormap pixels.
3626%
3627*/
cristya6577ff2011-09-02 19:54:26 +00003628MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003629 NexusInfo *nexus_info)
3630{
3631 CacheInfo
3632 *cache_info;
3633
cristye7cc7cf2010-09-21 13:26:47 +00003634 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003635 cache_info=(CacheInfo *) cache;
3636 assert(cache_info->signature == MagickSignature);
3637 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003638 return((Quantum *) NULL);
3639 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003640}
3641
3642/*
3643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3644% %
3645% %
3646% %
cristy4ee2b0c2012-05-15 00:30:35 +00003647+ I s P i x e l C a c h e I n C o r e %
3648% %
3649% %
3650% %
3651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3652%
3653% IsPixelCacheInCore() returns MagickTrue if the pixel cache is memory based
3654% otherwise MagickFalse.
3655%
3656% The format of the IsPixelCacheInCore() method is:
3657%
3658% MagickBooleanType IsPixelCacheInCore(const Image *image)
3659%
3660% A description of each parameter follows:
3661%
3662% o image: the image.
3663%
3664*/
3665MagickExport MagickBooleanType IsPixelCacheInCore(const Image *image)
3666{
3667 CacheInfo
3668 *cache_info;
3669
3670 assert(image != (Image *) NULL);
3671 assert(image->signature == MagickSignature);
3672 assert(image->cache != (Cache) NULL);
3673 cache_info=(CacheInfo *) image->cache;
3674 return(cache_info->type == DiskCache ? MagickFalse : MagickTrue);
3675}
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}