blob: 75d5da1ba5401a201cbffab0d9c8ba053be3c4d1 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
cristyadf82722012-05-11 17:34:16 +000057#include "MagickCore/memory-private.h"
cristyd2d11ec2012-03-28 13:53:49 +000058#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000059#include "MagickCore/pixel.h"
60#include "MagickCore/pixel-accessor.h"
61#include "MagickCore/policy.h"
62#include "MagickCore/quantum.h"
63#include "MagickCore/random_.h"
64#include "MagickCore/resource_.h"
65#include "MagickCore/semaphore.h"
66#include "MagickCore/splay-tree.h"
67#include "MagickCore/string_.h"
68#include "MagickCore/string-private.h"
69#include "MagickCore/thread-private.h"
70#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000071#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000072#if defined(MAGICKCORE_ZLIB_DELEGATE)
73#include "zlib.h"
74#endif
75
76/*
cristy30097232010-07-01 02:16:30 +000077 Define declarations.
78*/
79#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
cristyc11dace2012-01-24 16:39:46 +000080#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
81 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
cristy30097232010-07-01 02:16:30 +000082
83/*
cristy3ed852e2009-09-05 21:47:34 +000084 Typedef declarations.
85*/
86typedef struct _MagickModulo
87{
cristybb503372010-05-27 20:51:26 +000088 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000089 quotient,
90 remainder;
91} MagickModulo;
92
93struct _NexusInfo
94{
95 MagickBooleanType
96 mapped;
97
98 RectangleInfo
99 region;
100
101 MagickSizeType
102 length;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000105 *cache,
106 *pixels;
107
cristy4c08aed2011-07-01 19:47:50 +0000108 void
109 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000110
cristybb503372010-05-27 20:51:26 +0000111 size_t
cristy3ed852e2009-09-05 21:47:34 +0000112 signature;
113};
114
115/*
116 Forward declarations.
117*/
118#if defined(__cplusplus) || defined(c_plusplus)
119extern "C" {
120#endif
121
cristy19596d62012-02-19 00:24:59 +0000122static Cache
123 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
124 magick_hot_spot;
125
cristy4c08aed2011-07-01 19:47:50 +0000126static const Quantum
cristybb503372010-05-27 20:51:26 +0000127 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000128 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000129 *GetVirtualPixelsCache(const Image *);
130
cristy4c08aed2011-07-01 19:47:50 +0000131static const void
132 *GetVirtualMetacontentFromCache(const Image *);
133
cristy3ed852e2009-09-05 21:47:34 +0000134static MagickBooleanType
cristy74ce05d2012-05-06 18:41:18 +0000135 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
136 ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000137 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000138 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000139 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000140 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000141 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
142 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000143 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000144 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
145
cristy4c08aed2011-07-01 19:47:50 +0000146static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000147 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
148 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000149 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
150 const size_t,ExceptionInfo *),
cristy265a2b22012-05-11 12:48:50 +0000151 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
152 NexusInfo *,ExceptionInfo *) magick_hot_spot;
cristy3ed852e2009-09-05 21:47:34 +0000153
154#if defined(__cplusplus) || defined(c_plusplus)
155}
156#endif
157
158/*
159 Global declarations.
160*/
161static volatile MagickBooleanType
162 instantiate_cache = MagickFalse;
163
164static SemaphoreInfo
165 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000166
167/*
168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169% %
170% %
171% %
172+ A c q u i r e P i x e l C a c h e %
173% %
174% %
175% %
176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177%
178% AcquirePixelCache() acquires a pixel cache.
179%
180% The format of the AcquirePixelCache() method is:
181%
cristybb503372010-05-27 20:51:26 +0000182% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000183%
184% A description of each parameter follows:
185%
186% o number_threads: the number of nexus threads.
187%
188*/
cristya6577ff2011-09-02 19:54:26 +0000189MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000190{
191 CacheInfo
192 *cache_info;
193
cristya64b85d2011-09-14 01:02:31 +0000194 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000195 if (cache_info == (CacheInfo *) NULL)
196 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
197 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
198 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000199 cache_info->mode=IOMode;
cristyc511e882012-04-16 21:11:14 +0000200 cache_info->colorspace=sRGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +0000201 cache_info->file=(-1);
202 cache_info->id=GetMagickThreadId();
203 cache_info->number_threads=number_threads;
204 if (number_threads == 0)
cristyfeeb98d2012-05-09 16:32:12 +0000205 cache_info->number_threads=GetOpenMPMaximumThreads();
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
207 if (cache_info->nexus_info == (NexusInfo **) NULL)
208 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000209 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000210 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000211 cache_info->disk_semaphore=AllocateSemaphoreInfo();
212 cache_info->debug=IsEventLogging();
213 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000214 return((Cache ) cache_info);
215}
216
217/*
218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219% %
220% %
221% %
222% A c q u i r e P i x e l C a c h e N e x u s %
223% %
224% %
225% %
226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227%
228% AcquirePixelCacheNexus() allocates the NexusInfo structure.
229%
230% The format of the AcquirePixelCacheNexus method is:
231%
cristybb503372010-05-27 20:51:26 +0000232% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000233%
234% A description of each parameter follows:
235%
236% o number_threads: the number of nexus threads.
237%
238*/
cristya6577ff2011-09-02 19:54:26 +0000239MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000240{
cristy3ed852e2009-09-05 21:47:34 +0000241 NexusInfo
242 **nexus_info;
243
cristye076a6e2010-08-15 19:59:43 +0000244 register ssize_t
245 i;
246
cristy64c3edf2012-04-13 18:50:13 +0000247 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000248 sizeof(*nexus_info));
249 if (nexus_info == (NexusInfo **) NULL)
250 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000251 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
252 sizeof(**nexus_info));
253 if (nexus_info[0] == (NexusInfo *) NULL)
254 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
255 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000256 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000257 {
cristye5f87c82012-02-14 12:44:17 +0000258 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000259 nexus_info[i]->signature=MagickSignature;
260 }
261 return(nexus_info);
262}
263
264/*
265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266% %
267% %
268% %
cristyd43a46b2010-01-21 02:13:41 +0000269+ A c q u i r e P i x e l C a c h e P i x e l s %
270% %
271% %
272% %
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274%
275% AcquirePixelCachePixels() returns the pixels associated with the specified
276% image.
277%
278% The format of the AcquirePixelCachePixels() method is:
279%
280% const void *AcquirePixelCachePixels(const Image *image,
281% MagickSizeType *length,ExceptionInfo *exception)
282%
283% A description of each parameter follows:
284%
285% o image: the image.
286%
287% o length: the pixel cache length.
288%
289% o exception: return any errors or warnings in this structure.
290%
291*/
cristyd1dd6e42011-09-04 01:46:08 +0000292MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000293 MagickSizeType *length,ExceptionInfo *exception)
294{
295 CacheInfo
296 *cache_info;
297
298 assert(image != (const Image *) NULL);
299 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000300 assert(exception != (ExceptionInfo *) NULL);
301 assert(exception->signature == MagickSignature);
302 assert(image->cache != (Cache) NULL);
303 cache_info=(CacheInfo *) image->cache;
304 assert(cache_info->signature == MagickSignature);
305 *length=0;
306 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
307 return((const void *) NULL);
308 *length=cache_info->length;
309 return((const void *) cache_info->pixels);
310}
311
312/*
313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314% %
315% %
316% %
cristyf34a1452009-10-24 22:29:27 +0000317+ C a c h e C o m p o n e n t G e n e s i s %
318% %
319% %
320% %
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322%
323% CacheComponentGenesis() instantiates the cache component.
324%
325% The format of the CacheComponentGenesis method is:
326%
327% MagickBooleanType CacheComponentGenesis(void)
328%
329*/
cristy5ff4eaf2011-09-03 01:38:02 +0000330MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000331{
cristy165b6092009-10-26 13:52:10 +0000332 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000333 return(MagickTrue);
334}
335
336/*
337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338% %
339% %
340% %
341+ C a c h e C o m p o n e n t T e r m i n u s %
342% %
343% %
344% %
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346%
347% CacheComponentTerminus() destroys the cache component.
348%
349% The format of the CacheComponentTerminus() method is:
350%
351% CacheComponentTerminus(void)
352%
353*/
cristy5ff4eaf2011-09-03 01:38:02 +0000354MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000355{
cristy18b17442009-10-25 18:36:48 +0000356 if (cache_semaphore == (SemaphoreInfo *) NULL)
357 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000358 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000359 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000360 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000361 DestroySemaphoreInfo(&cache_semaphore);
362}
363
364/*
365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366% %
367% %
368% %
cristy3ed852e2009-09-05 21:47:34 +0000369+ C l o n e P i x e l C a c h e %
370% %
371% %
372% %
373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374%
375% ClonePixelCache() clones a pixel cache.
376%
377% The format of the ClonePixelCache() method is:
378%
379% Cache ClonePixelCache(const Cache cache)
380%
381% A description of each parameter follows:
382%
383% o cache: the pixel cache.
384%
385*/
cristya6577ff2011-09-02 19:54:26 +0000386MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000387{
388 CacheInfo
389 *clone_info;
390
391 const CacheInfo
392 *cache_info;
393
cristy9f027d12011-09-21 01:17:17 +0000394 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000395 cache_info=(const CacheInfo *) cache;
396 assert(cache_info->signature == MagickSignature);
397 if (cache_info->debug != MagickFalse)
398 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
399 cache_info->filename);
400 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
401 if (clone_info == (Cache) NULL)
402 return((Cache) NULL);
403 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
404 return((Cache ) clone_info);
405}
406
407/*
408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
409% %
410% %
411% %
cristy60c44a82009-10-07 00:58:49 +0000412+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000413% %
414% %
415% %
416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
417% ClonePixelCachePixels() clones the source pixel cache to the destination
418% cache.
419%
420% The format of the ClonePixelCachePixels() method is:
421%
422% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
423% CacheInfo *source_info,ExceptionInfo *exception)
424%
425% A description of each parameter follows:
426%
427% o cache_info: the pixel cache.
428%
429% o source_info: the source pixel cache.
430%
431% o exception: return any errors or warnings in this structure.
432%
433*/
434
435static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
436{
437 int
438 status;
439
cristy5ee247a2010-02-12 15:42:34 +0000440 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000441 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000442 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000443 {
444 status=close(cache_info->file);
445 cache_info->file=(-1);
446 RelinquishMagickResource(FileResource,1);
447 }
cristyf84a1932010-01-03 18:00:18 +0000448 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000449 return(status == -1 ? MagickFalse : MagickTrue);
450}
451
cristy3ed852e2009-09-05 21:47:34 +0000452static inline MagickSizeType MagickMax(const MagickSizeType x,
453 const MagickSizeType y)
454{
455 if (x > y)
456 return(x);
457 return(y);
458}
459
460static inline MagickSizeType MagickMin(const MagickSizeType x,
461 const MagickSizeType y)
462{
463 if (x < y)
464 return(x);
465 return(y);
466}
467
468static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
469 const MapMode mode)
470{
471 int
472 file;
473
474 /*
475 Open pixel cache on disk.
476 */
cristyf84a1932010-01-03 18:00:18 +0000477 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000478 if (cache_info->file != -1)
479 {
cristyf84a1932010-01-03 18:00:18 +0000480 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000481 return(MagickTrue); /* cache already open */
482 }
cristy3ed852e2009-09-05 21:47:34 +0000483 if (*cache_info->cache_filename == '\0')
484 file=AcquireUniqueFileResource(cache_info->cache_filename);
485 else
486 switch (mode)
487 {
488 case ReadMode:
489 {
cristy18c6c272011-09-23 14:40:37 +0000490 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000491 break;
492 }
493 case WriteMode:
494 {
cristy18c6c272011-09-23 14:40:37 +0000495 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
496 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000497 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000498 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000499 break;
500 }
501 case IOMode:
502 default:
503 {
cristy18c6c272011-09-23 14:40:37 +0000504 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000505 O_EXCL,S_MODE);
506 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000507 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000508 break;
509 }
510 }
511 if (file == -1)
512 {
cristyf84a1932010-01-03 18:00:18 +0000513 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000514 return(MagickFalse);
515 }
516 (void) AcquireMagickResource(FileResource,1);
517 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000518 cache_info->mode=mode;
cristyf84a1932010-01-03 18:00:18 +0000519 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000520 return(MagickTrue);
521}
522
cristyf1832792012-05-08 18:38:18 +0000523static inline MagickOffsetType ReadPixelCacheRegion(
524 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
525 const MagickSizeType length,unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000526{
527 register MagickOffsetType
528 i;
529
530 ssize_t
531 count;
532
533#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000534 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000535 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000536 {
cristyf84a1932010-01-03 18:00:18 +0000537 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000538 return((MagickOffsetType) -1);
539 }
540#endif
541 count=0;
542 for (i=0; i < (MagickOffsetType) length; i+=count)
543 {
544#if !defined(MAGICKCORE_HAVE_PREAD)
545 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
546 (MagickSizeType) SSIZE_MAX));
547#else
548 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000549 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000550#endif
551 if (count > 0)
552 continue;
553 count=0;
554 if (errno != EINTR)
555 {
556 i=(-1);
557 break;
558 }
559 }
560#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000561 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000562#endif
563 return(i);
564}
565
cristyf1832792012-05-08 18:38:18 +0000566static inline MagickOffsetType WritePixelCacheRegion(
567 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
568 const MagickSizeType length,const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000569{
570 register MagickOffsetType
571 i;
572
573 ssize_t
574 count;
575
576#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000578 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return((MagickOffsetType) -1);
582 }
583#endif
584 count=0;
585 for (i=0; i < (MagickOffsetType) length; i+=count)
586 {
587#if !defined(MAGICKCORE_HAVE_PWRITE)
588 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
589 (MagickSizeType) SSIZE_MAX));
590#else
591 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000592 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000593#endif
594 if (count > 0)
595 continue;
596 count=0;
597 if (errno != EINTR)
598 {
599 i=(-1);
600 break;
601 }
602 }
603#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000604 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000605#endif
606 return(i);
607}
608
cristy4c08aed2011-07-01 19:47:50 +0000609static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000610 CacheInfo *cache_info,ExceptionInfo *exception)
611{
612 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000613 count;
cristy3ed852e2009-09-05 21:47:34 +0000614
cristy4c08aed2011-07-01 19:47:50 +0000615 register MagickOffsetType
616 i;
cristye076a6e2010-08-15 19:59:43 +0000617
cristybb503372010-05-27 20:51:26 +0000618 size_t
cristy4c08aed2011-07-01 19:47:50 +0000619 length;
cristy3ed852e2009-09-05 21:47:34 +0000620
cristy4c08aed2011-07-01 19:47:50 +0000621 unsigned char
622 *blob;
623
624 /*
625 Clone pixel cache (both caches on disk).
626 */
cristy3ed852e2009-09-05 21:47:34 +0000627 if (cache_info->debug != MagickFalse)
628 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000629 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000630 sizeof(*blob));
631 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000632 {
cristy4c08aed2011-07-01 19:47:50 +0000633 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000634 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000635 cache_info->filename);
636 return(MagickFalse);
637 }
cristy3dedf062011-07-02 14:07:40 +0000638 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000639 {
640 blob=(unsigned char *) RelinquishMagickMemory(blob);
641 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
642 cache_info->cache_filename);
643 return(MagickFalse);
644 }
cristy3dedf062011-07-02 14:07:40 +0000645 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000646 {
647 (void) ClosePixelCacheOnDisk(cache_info);
648 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000649 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
650 clone_info->cache_filename);
651 return(MagickFalse);
652 }
cristy4c08aed2011-07-01 19:47:50 +0000653 count=0;
654 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000655 {
cristy4c08aed2011-07-01 19:47:50 +0000656 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
657 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
658 blob);
659 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000660 {
cristy4c08aed2011-07-01 19:47:50 +0000661 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
662 cache_info->cache_filename);
663 break;
cristy3ed852e2009-09-05 21:47:34 +0000664 }
cristy4c08aed2011-07-01 19:47:50 +0000665 length=(size_t) count;
666 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
667 if ((MagickSizeType) count != length)
668 {
669 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
670 clone_info->cache_filename);
671 break;
672 }
673 }
674 (void) ClosePixelCacheOnDisk(clone_info);
675 (void) ClosePixelCacheOnDisk(cache_info);
676 blob=(unsigned char *) RelinquishMagickMemory(blob);
677 if (i < (MagickOffsetType) cache_info->length)
678 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000679 return(MagickTrue);
680}
681
cristyfd24a062012-01-02 14:46:34 +0000682static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000683 CacheInfo *cache_info,ExceptionInfo *exception)
684{
685 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000686 count;
cristy3ed852e2009-09-05 21:47:34 +0000687
cristy4c08aed2011-07-01 19:47:50 +0000688 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000689 {
cristy3ed852e2009-09-05 21:47:34 +0000690 /*
cristy4c08aed2011-07-01 19:47:50 +0000691 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000692 */
cristy4c08aed2011-07-01 19:47:50 +0000693 if (cache_info->debug != MagickFalse)
694 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
695 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
696 cache_info->length);
697 return(MagickTrue);
698 }
699 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
700 {
701 /*
702 Clone pixel cache (one cache on disk, one in memory).
703 */
704 if (cache_info->debug != MagickFalse)
705 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
706 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000707 {
cristy4c08aed2011-07-01 19:47:50 +0000708 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000709 cache_info->cache_filename);
710 return(MagickFalse);
711 }
cristy4c08aed2011-07-01 19:47:50 +0000712 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
713 cache_info->length,(unsigned char *) clone_info->pixels);
714 (void) ClosePixelCacheOnDisk(cache_info);
715 if ((MagickSizeType) count != cache_info->length)
716 {
717 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
718 cache_info->cache_filename);
719 return(MagickFalse);
720 }
721 return(MagickTrue);
722 }
723 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
724 {
725 /*
726 Clone pixel cache (one cache on disk, one in memory).
727 */
728 if (clone_info->debug != MagickFalse)
729 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
730 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
731 {
732 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
733 clone_info->cache_filename);
734 return(MagickFalse);
735 }
736 count=WritePixelCacheRegion(clone_info,clone_info->offset,
737 clone_info->length,(unsigned char *) cache_info->pixels);
738 (void) ClosePixelCacheOnDisk(clone_info);
739 if ((MagickSizeType) count != clone_info->length)
740 {
741 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
742 clone_info->cache_filename);
743 return(MagickFalse);
744 }
745 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000746 }
747 /*
cristy4c08aed2011-07-01 19:47:50 +0000748 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000749 */
cristy4c08aed2011-07-01 19:47:50 +0000750 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000751}
752
cristyfd24a062012-01-02 14:46:34 +0000753static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000754 CacheInfo *cache_info,ExceptionInfo *exception)
755{
cristy4c08aed2011-07-01 19:47:50 +0000756 MagickBooleanType
757 status;
cristy3ed852e2009-09-05 21:47:34 +0000758
cristy4c08aed2011-07-01 19:47:50 +0000759 MagickOffsetType
760 cache_offset,
761 clone_offset,
762 count;
763
764 register ssize_t
765 x;
766
cristyfd24a062012-01-02 14:46:34 +0000767 register unsigned char
768 *p;
769
cristy4c08aed2011-07-01 19:47:50 +0000770 size_t
cristy3ed852e2009-09-05 21:47:34 +0000771 length;
772
cristy4c08aed2011-07-01 19:47:50 +0000773 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000774 y;
775
cristy4c08aed2011-07-01 19:47:50 +0000776 unsigned char
777 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000778
cristy4c08aed2011-07-01 19:47:50 +0000779 /*
780 Clone pixel cache (unoptimized).
781 */
cristy3ed852e2009-09-05 21:47:34 +0000782 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000783 {
cristy4c08aed2011-07-01 19:47:50 +0000784 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
786 else
787 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
789 else
790 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
792 else
793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
794 }
cristyed231572011-07-14 02:18:59 +0000795 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
796 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000797 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000798 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000799 if (blob == (unsigned char *) NULL)
800 {
801 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000802 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000803 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000804 return(MagickFalse);
805 }
cristy4c08aed2011-07-01 19:47:50 +0000806 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
807 cache_offset=0;
808 clone_offset=0;
809 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000810 {
cristy4c08aed2011-07-01 19:47:50 +0000811 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 blob=(unsigned char *) RelinquishMagickMemory(blob);
814 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000815 cache_info->cache_filename);
816 return(MagickFalse);
817 }
cristy4c08aed2011-07-01 19:47:50 +0000818 cache_offset=cache_info->offset;
819 }
820 if (clone_info->type == DiskCache)
821 {
cristy3dedf062011-07-02 14:07:40 +0000822 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000823 {
cristy4c08aed2011-07-01 19:47:50 +0000824 blob=(unsigned char *) RelinquishMagickMemory(blob);
825 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
826 clone_info->cache_filename);
827 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000828 }
cristy4c08aed2011-07-01 19:47:50 +0000829 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000830 }
831 /*
cristy4c08aed2011-07-01 19:47:50 +0000832 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000833 */
cristy4c08aed2011-07-01 19:47:50 +0000834 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000835 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000836 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000837 {
cristy4c08aed2011-07-01 19:47:50 +0000838 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000839 {
cristy9e0719b2011-12-29 03:45:45 +0000840 register ssize_t
841 i;
842
cristy3ed852e2009-09-05 21:47:34 +0000843 /*
cristy4c08aed2011-07-01 19:47:50 +0000844 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000845 */
cristyed231572011-07-14 02:18:59 +0000846 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000847 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000848 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000849 else
850 {
cristyfd24a062012-01-02 14:46:34 +0000851 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000852 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000853 {
cristy4c08aed2011-07-01 19:47:50 +0000854 status=MagickFalse;
855 break;
cristy3ed852e2009-09-05 21:47:34 +0000856 }
857 }
cristy4c08aed2011-07-01 19:47:50 +0000858 cache_offset+=length;
859 if ((y < (ssize_t) clone_info->rows) &&
860 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000861 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000862 {
cristy9e0719b2011-12-29 03:45:45 +0000863 PixelChannel
864 channel;
865
866 PixelTrait
867 traits;
868
869 ssize_t
870 offset;
871
cristy4c08aed2011-07-01 19:47:50 +0000872 /*
cristy3b8fe922011-12-29 18:56:23 +0000873 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000874 */
cristy9e0719b2011-12-29 03:45:45 +0000875 channel=clone_info->channel_map[i].channel;
876 traits=cache_info->channel_map[channel].traits;
877 if (traits == UndefinedPixelTrait)
878 {
cristy0f4425e2011-12-31 20:33:02 +0000879 clone_offset+=sizeof(Quantum);
880 continue;
cristy9e0719b2011-12-29 03:45:45 +0000881 }
cristy0f4425e2011-12-31 20:33:02 +0000882 offset=cache_info->channel_map[channel].offset;
883 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000884 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
885 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000886 else
887 {
cristy0f4425e2011-12-31 20:33:02 +0000888 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000889 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000890 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000891 {
cristy0f4425e2011-12-31 20:33:02 +0000892 status=MagickFalse;
893 break;
cristy4c08aed2011-07-01 19:47:50 +0000894 }
895 }
cristy9e0719b2011-12-29 03:45:45 +0000896 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000897 }
898 }
cristyac245f82012-05-05 17:13:57 +0000899 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000900 {
901 /*
902 Set remaining columns as undefined.
903 */
cristy888e6132012-04-23 19:54:54 +0000904 length=clone_info->number_channels*sizeof(Quantum);
905 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
906 for ( ; x < (ssize_t) clone_info->columns; x++)
907 {
908 if (clone_info->type != DiskCache)
909 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
910 blob,length);
911 else
912 {
913 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
914 if ((MagickSizeType) count != length)
915 {
916 status=MagickFalse;
917 break;
cristye04362f2012-04-23 15:33:05 +0000918 }
cristy888e6132012-04-23 19:54:54 +0000919 }
920 clone_offset+=length;
921 }
cristye04362f2012-04-23 15:33:05 +0000922 }
cristy4c08aed2011-07-01 19:47:50 +0000923 }
cristyed231572011-07-14 02:18:59 +0000924 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000925 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
926 for ( ; y < (ssize_t) clone_info->rows; y++)
927 {
928 /*
cristy9e0719b2011-12-29 03:45:45 +0000929 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000930 */
931 for (x=0; x < (ssize_t) clone_info->columns; x++)
932 {
933 if (clone_info->type != DiskCache)
934 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
935 length);
936 else
937 {
938 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
939 if ((MagickSizeType) count != length)
940 {
941 status=MagickFalse;
942 break;
943 }
944 }
945 clone_offset+=length;
946 }
947 }
cristy9e0719b2011-12-29 03:45:45 +0000948 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000949 (clone_info->metacontent_extent != 0))
950 {
951 /*
952 Clone metacontent.
953 */
954 for (y=0; y < (ssize_t) cache_info->rows; y++)
955 {
956 for (x=0; x < (ssize_t) cache_info->columns; x++)
957 {
958 /*
959 Read a set of metacontent.
960 */
961 length=cache_info->metacontent_extent;
962 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000963 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000964 else
965 {
cristyfd24a062012-01-02 14:46:34 +0000966 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000967 if ((MagickSizeType) count != length)
968 {
969 status=MagickFalse;
970 break;
971 }
972 }
973 cache_offset+=length;
974 if ((y < (ssize_t) clone_info->rows) &&
975 (x < (ssize_t) clone_info->columns))
976 {
977 /*
978 Write a set of metacontent.
979 */
980 length=clone_info->metacontent_extent;
981 if (clone_info->type != DiskCache)
982 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000983 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000984 else
985 {
cristyfd24a062012-01-02 14:46:34 +0000986 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000987 if ((MagickSizeType) count != length)
988 {
989 status=MagickFalse;
990 break;
991 }
992 }
993 clone_offset+=length;
994 }
995 }
996 length=clone_info->metacontent_extent;
997 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
998 for ( ; x < (ssize_t) clone_info->columns; x++)
999 {
1000 /*
cristy9e0719b2011-12-29 03:45:45 +00001001 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001002 */
1003 if (clone_info->type != DiskCache)
1004 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1005 blob,length);
1006 else
1007 {
cristy208b1002011-08-07 18:51:50 +00001008 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001009 if ((MagickSizeType) count != length)
1010 {
1011 status=MagickFalse;
1012 break;
1013 }
1014 }
1015 clone_offset+=length;
1016 }
1017 }
cristyac245f82012-05-05 17:13:57 +00001018 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001019 {
cristye04362f2012-04-23 15:33:05 +00001020 /*
1021 Set remaining rows as undefined.
1022 */
cristy888e6132012-04-23 19:54:54 +00001023 length=clone_info->metacontent_extent;
1024 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1025 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001026 {
cristy888e6132012-04-23 19:54:54 +00001027 for (x=0; x < (ssize_t) clone_info->columns; x++)
1028 {
1029 if (clone_info->type != DiskCache)
1030 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1031 blob,length);
1032 else
1033 {
1034 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1035 blob);
1036 if ((MagickSizeType) count != length)
1037 {
1038 status=MagickFalse;
1039 break;
1040 }
1041 }
1042 clone_offset+=length;
1043 }
cristye04362f2012-04-23 15:33:05 +00001044 }
cristy4c08aed2011-07-01 19:47:50 +00001045 }
cristy4c08aed2011-07-01 19:47:50 +00001046 }
1047 if (clone_info->type == DiskCache)
1048 (void) ClosePixelCacheOnDisk(clone_info);
1049 if (cache_info->type == DiskCache)
1050 (void) ClosePixelCacheOnDisk(cache_info);
1051 blob=(unsigned char *) RelinquishMagickMemory(blob);
1052 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001053}
1054
1055static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1056 CacheInfo *cache_info,ExceptionInfo *exception)
1057{
cristy3dfccb22011-12-28 21:47:20 +00001058 PixelChannelMap
1059 *p,
1060 *q;
1061
cristy5a7fbfb2010-11-06 16:10:59 +00001062 if (cache_info->type == PingCache)
1063 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001064 p=cache_info->channel_map;
1065 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001066 if ((cache_info->columns == clone_info->columns) &&
1067 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001068 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001069 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001070 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001071 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1072 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001073}
1074
1075/*
1076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1077% %
1078% %
1079% %
1080+ C l o n e P i x e l C a c h e M e t h o d s %
1081% %
1082% %
1083% %
1084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1085%
1086% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1087% another.
1088%
1089% The format of the ClonePixelCacheMethods() method is:
1090%
1091% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1092%
1093% A description of each parameter follows:
1094%
1095% o clone: Specifies a pointer to a Cache structure.
1096%
1097% o cache: the pixel cache.
1098%
1099*/
cristya6577ff2011-09-02 19:54:26 +00001100MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001101{
1102 CacheInfo
1103 *cache_info,
1104 *source_info;
1105
1106 assert(clone != (Cache) NULL);
1107 source_info=(CacheInfo *) clone;
1108 assert(source_info->signature == MagickSignature);
1109 if (source_info->debug != MagickFalse)
1110 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1111 source_info->filename);
1112 assert(cache != (Cache) NULL);
1113 cache_info=(CacheInfo *) cache;
1114 assert(cache_info->signature == MagickSignature);
1115 source_info->methods=cache_info->methods;
1116}
1117
1118/*
1119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1120% %
1121% %
1122% %
1123+ D e s t r o y I m a g e P i x e l C a c h e %
1124% %
1125% %
1126% %
1127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1128%
1129% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1130%
1131% The format of the DestroyImagePixelCache() method is:
1132%
1133% void DestroyImagePixelCache(Image *image)
1134%
1135% A description of each parameter follows:
1136%
1137% o image: the image.
1138%
1139*/
1140static void DestroyImagePixelCache(Image *image)
1141{
1142 assert(image != (Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 if (image->debug != MagickFalse)
1145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1146 if (image->cache == (void *) NULL)
1147 return;
1148 image->cache=DestroyPixelCache(image->cache);
1149}
1150
1151/*
1152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1153% %
1154% %
1155% %
1156+ D e s t r o y I m a g e P i x e l s %
1157% %
1158% %
1159% %
1160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1161%
1162% DestroyImagePixels() deallocates memory associated with the pixel cache.
1163%
1164% The format of the DestroyImagePixels() method is:
1165%
1166% void DestroyImagePixels(Image *image)
1167%
1168% A description of each parameter follows:
1169%
1170% o image: the image.
1171%
1172*/
1173MagickExport void DestroyImagePixels(Image *image)
1174{
1175 CacheInfo
1176 *cache_info;
1177
1178 assert(image != (const Image *) NULL);
1179 assert(image->signature == MagickSignature);
1180 if (image->debug != MagickFalse)
1181 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1182 assert(image->cache != (Cache) NULL);
1183 cache_info=(CacheInfo *) image->cache;
1184 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001185 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1186 {
1187 cache_info->methods.destroy_pixel_handler(image);
1188 return;
1189 }
cristy2036f5c2010-09-19 21:18:17 +00001190 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001191}
1192
1193/*
1194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1195% %
1196% %
1197% %
1198+ D e s t r o y P i x e l C a c h e %
1199% %
1200% %
1201% %
1202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203%
1204% DestroyPixelCache() deallocates memory associated with the pixel cache.
1205%
1206% The format of the DestroyPixelCache() method is:
1207%
1208% Cache DestroyPixelCache(Cache cache)
1209%
1210% A description of each parameter follows:
1211%
1212% o cache: the pixel cache.
1213%
1214*/
1215
1216static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1217{
1218 switch (cache_info->type)
1219 {
1220 case MemoryCache:
1221 {
1222 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001223 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001224 cache_info->pixels);
1225 else
cristy4c08aed2011-07-01 19:47:50 +00001226 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001227 (size_t) cache_info->length);
1228 RelinquishMagickResource(MemoryResource,cache_info->length);
1229 break;
1230 }
1231 case MapCache:
1232 {
cristy4c08aed2011-07-01 19:47:50 +00001233 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001234 cache_info->length);
1235 RelinquishMagickResource(MapResource,cache_info->length);
1236 }
1237 case DiskCache:
1238 {
1239 if (cache_info->file != -1)
1240 (void) ClosePixelCacheOnDisk(cache_info);
1241 RelinquishMagickResource(DiskResource,cache_info->length);
1242 break;
1243 }
1244 default:
1245 break;
1246 }
1247 cache_info->type=UndefinedCache;
1248 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001249 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001250}
1251
cristya6577ff2011-09-02 19:54:26 +00001252MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001253{
1254 CacheInfo
1255 *cache_info;
1256
cristy3ed852e2009-09-05 21:47:34 +00001257 assert(cache != (Cache) NULL);
1258 cache_info=(CacheInfo *) cache;
1259 assert(cache_info->signature == MagickSignature);
1260 if (cache_info->debug != MagickFalse)
1261 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1262 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001263 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001264 cache_info->reference_count--;
1265 if (cache_info->reference_count != 0)
1266 {
cristyf84a1932010-01-03 18:00:18 +00001267 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001268 return((Cache) NULL);
1269 }
cristyf84a1932010-01-03 18:00:18 +00001270 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001271 if (cache_info->debug != MagickFalse)
1272 {
1273 char
1274 message[MaxTextExtent];
1275
cristyb51dff52011-05-19 16:55:47 +00001276 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001277 cache_info->filename);
1278 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1279 }
cristyc2e1bdd2009-09-10 23:43:34 +00001280 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1281 (cache_info->type != DiskCache)))
1282 RelinquishPixelCachePixels(cache_info);
1283 else
1284 {
1285 RelinquishPixelCachePixels(cache_info);
1286 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1287 }
cristy3ed852e2009-09-05 21:47:34 +00001288 *cache_info->cache_filename='\0';
1289 if (cache_info->nexus_info != (NexusInfo **) NULL)
1290 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1291 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001292 if (cache_info->random_info != (RandomInfo *) NULL)
1293 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001294 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1295 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1296 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1297 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001298 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001299 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001300 cache=(Cache) NULL;
1301 return(cache);
1302}
1303
1304/*
1305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1306% %
1307% %
1308% %
1309+ D e s t r o y P i x e l C a c h e N e x u s %
1310% %
1311% %
1312% %
1313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1314%
1315% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1316%
1317% The format of the DestroyPixelCacheNexus() method is:
1318%
1319% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001320% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001321%
1322% A description of each parameter follows:
1323%
1324% o nexus_info: the nexus to destroy.
1325%
1326% o number_threads: the number of nexus threads.
1327%
1328*/
1329
1330static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1331{
1332 if (nexus_info->mapped == MagickFalse)
cristy64c3edf2012-04-13 18:50:13 +00001333 (void) RelinquishMagickMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001334 else
1335 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001336 nexus_info->cache=(Quantum *) NULL;
1337 nexus_info->pixels=(Quantum *) NULL;
1338 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001339 nexus_info->length=0;
1340 nexus_info->mapped=MagickFalse;
1341}
1342
cristya6577ff2011-09-02 19:54:26 +00001343MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001344 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001345{
cristybb503372010-05-27 20:51:26 +00001346 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001347 i;
1348
1349 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001350 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001351 {
cristy4c08aed2011-07-01 19:47:50 +00001352 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001353 RelinquishCacheNexusPixels(nexus_info[i]);
1354 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001355 }
cristye5f87c82012-02-14 12:44:17 +00001356 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001357 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001358 return(nexus_info);
1359}
1360
1361/*
1362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1363% %
1364% %
1365% %
cristy4c08aed2011-07-01 19:47:50 +00001366% G e t A u t h e n t i c M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00001367% %
1368% %
1369% %
1370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371%
cristy4c08aed2011-07-01 19:47:50 +00001372% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1373% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1374% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001375%
cristy4c08aed2011-07-01 19:47:50 +00001376% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001377%
cristy4c08aed2011-07-01 19:47:50 +00001378% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001379%
1380% A description of each parameter follows:
1381%
1382% o image: the image.
1383%
1384*/
cristy4c08aed2011-07-01 19:47:50 +00001385MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001386{
1387 CacheInfo
1388 *cache_info;
1389
cristy5c9e6f22010-09-17 17:31:01 +00001390 const int
1391 id = GetOpenMPThreadId();
1392
cristy4c08aed2011-07-01 19:47:50 +00001393 void
1394 *metacontent;
1395
cristye7cc7cf2010-09-21 13:26:47 +00001396 assert(image != (const Image *) NULL);
1397 assert(image->signature == MagickSignature);
1398 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001399 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001400 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001401 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1402 (GetAuthenticMetacontentFromHandler) NULL)
1403 {
1404 metacontent=cache_info->methods.
1405 get_authentic_metacontent_from_handler(image);
1406 return(metacontent);
1407 }
cristy6ebe97c2010-07-03 01:17:28 +00001408 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001409 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1410 cache_info->nexus_info[id]);
1411 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001412}
1413
1414/*
1415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416% %
1417% %
1418% %
cristy4c08aed2011-07-01 19:47:50 +00001419+ G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00001420% %
1421% %
1422% %
1423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1424%
cristy4c08aed2011-07-01 19:47:50 +00001425% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1426% with the last call to QueueAuthenticPixelsCache() or
1427% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001428%
cristy4c08aed2011-07-01 19:47:50 +00001429% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001430%
cristy4c08aed2011-07-01 19:47:50 +00001431% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001432%
1433% A description of each parameter follows:
1434%
1435% o image: the image.
1436%
1437*/
cristy4c08aed2011-07-01 19:47:50 +00001438static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001439{
1440 CacheInfo
1441 *cache_info;
1442
cristy2036f5c2010-09-19 21:18:17 +00001443 const int
1444 id = GetOpenMPThreadId();
1445
cristy4c08aed2011-07-01 19:47:50 +00001446 void
1447 *metacontent;
1448
cristy3ed852e2009-09-05 21:47:34 +00001449 assert(image != (const Image *) NULL);
1450 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001451 assert(image->cache != (Cache) NULL);
1452 cache_info=(CacheInfo *) image->cache;
1453 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001454 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001455 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1456 cache_info->nexus_info[id]);
1457 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001458}
1459
1460/*
1461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1462% %
1463% %
1464% %
1465+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1466% %
1467% %
1468% %
1469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1470%
1471% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1472% disk pixel cache as defined by the geometry parameters. A pointer to the
1473% pixels is returned if the pixels are transferred, otherwise a NULL is
1474% returned.
1475%
1476% The format of the GetAuthenticPixelCacheNexus() method is:
1477%
cristy4c08aed2011-07-01 19:47:50 +00001478% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001479% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001480% NexusInfo *nexus_info,ExceptionInfo *exception)
1481%
1482% A description of each parameter follows:
1483%
1484% o image: the image.
1485%
1486% o x,y,columns,rows: These values define the perimeter of a region of
1487% pixels.
1488%
1489% o nexus_info: the cache nexus to return.
1490%
1491% o exception: return any errors or warnings in this structure.
1492%
1493*/
1494
cristy7f69b802012-05-08 16:39:59 +00001495static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001496 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001497{
cristy4c08aed2011-07-01 19:47:50 +00001498 MagickBooleanType
1499 status;
1500
cristy3ed852e2009-09-05 21:47:34 +00001501 MagickOffsetType
1502 offset;
1503
cristy73724512010-04-12 14:43:14 +00001504 if (cache_info->type == PingCache)
1505 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001506 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1507 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001508 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001509 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001510 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001511}
1512
cristya6577ff2011-09-02 19:54:26 +00001513MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001514 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001515 NexusInfo *nexus_info,ExceptionInfo *exception)
1516{
1517 CacheInfo
1518 *cache_info;
1519
cristy4c08aed2011-07-01 19:47:50 +00001520 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001521 *q;
cristy3ed852e2009-09-05 21:47:34 +00001522
1523 /*
1524 Transfer pixels from the cache.
1525 */
1526 assert(image != (Image *) NULL);
1527 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001528 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1529 exception);
cristyacd2ed22011-08-30 01:44:23 +00001530 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001531 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001532 cache_info=(CacheInfo *) image->cache;
1533 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001534 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001535 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001536 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001537 return((Quantum *) NULL);
1538 if (cache_info->metacontent_extent != 0)
1539 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1540 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001541 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001542}
1543
1544/*
1545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546% %
1547% %
1548% %
1549+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1550% %
1551% %
1552% %
1553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1554%
1555% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1556% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1557%
1558% The format of the GetAuthenticPixelsFromCache() method is:
1559%
cristy4c08aed2011-07-01 19:47:50 +00001560% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001561%
1562% A description of each parameter follows:
1563%
1564% o image: the image.
1565%
1566*/
cristy4c08aed2011-07-01 19:47:50 +00001567static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001568{
1569 CacheInfo
1570 *cache_info;
1571
cristy5c9e6f22010-09-17 17:31:01 +00001572 const int
1573 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001574
cristye7cc7cf2010-09-21 13:26:47 +00001575 assert(image != (const Image *) NULL);
1576 assert(image->signature == MagickSignature);
1577 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001578 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001579 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001580 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001581 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001582}
1583
1584/*
1585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586% %
1587% %
1588% %
1589% G e t A u t h e n t i c P i x e l Q u e u e %
1590% %
1591% %
1592% %
1593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594%
cristy4c08aed2011-07-01 19:47:50 +00001595% GetAuthenticPixelQueue() returns the authentic pixels associated
1596% corresponding with the last call to QueueAuthenticPixels() or
1597% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001598%
1599% The format of the GetAuthenticPixelQueue() method is:
1600%
cristy4c08aed2011-07-01 19:47:50 +00001601% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001602%
1603% A description of each parameter follows:
1604%
1605% o image: the image.
1606%
1607*/
cristy4c08aed2011-07-01 19:47:50 +00001608MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001609{
1610 CacheInfo
1611 *cache_info;
1612
cristy2036f5c2010-09-19 21:18:17 +00001613 const int
1614 id = GetOpenMPThreadId();
1615
cristy3ed852e2009-09-05 21:47:34 +00001616 assert(image != (const Image *) NULL);
1617 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001618 assert(image->cache != (Cache) NULL);
1619 cache_info=(CacheInfo *) image->cache;
1620 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001621 if (cache_info->methods.get_authentic_pixels_from_handler !=
1622 (GetAuthenticPixelsFromHandler) NULL)
1623 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001624 assert(id < (int) cache_info->number_threads);
1625 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001626}
1627
1628/*
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630% %
1631% %
1632% %
1633% G e t A u t h e n t i c P i x e l s %
1634% %
1635% %
cristy4c08aed2011-07-01 19:47:50 +00001636% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001637%
1638% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001639% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001640% representing the region is returned, otherwise NULL is returned.
1641%
1642% The returned pointer may point to a temporary working copy of the pixels
1643% or it may point to the original pixels in memory. Performance is maximized
1644% if the selected region is part of one row, or one or more full rows, since
1645% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001646% if the image is in memory, or in a memory-mapped file. The returned pointer
1647% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001648%
1649% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001650% Quantum. If the image has corresponding metacontent,call
1651% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1652% meta-content corresponding to the region. Once the Quantum array has
1653% been updated, the changes must be saved back to the underlying image using
1654% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001655%
1656% The format of the GetAuthenticPixels() method is:
1657%
cristy4c08aed2011-07-01 19:47:50 +00001658% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001659% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001660% ExceptionInfo *exception)
1661%
1662% A description of each parameter follows:
1663%
1664% o image: the image.
1665%
1666% o x,y,columns,rows: These values define the perimeter of a region of
1667% pixels.
1668%
1669% o exception: return any errors or warnings in this structure.
1670%
1671*/
cristy4c08aed2011-07-01 19:47:50 +00001672MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001673 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001674 ExceptionInfo *exception)
1675{
1676 CacheInfo
1677 *cache_info;
1678
cristy2036f5c2010-09-19 21:18:17 +00001679 const int
1680 id = GetOpenMPThreadId();
1681
cristy4c08aed2011-07-01 19:47:50 +00001682 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001683 *q;
cristy4c08aed2011-07-01 19:47:50 +00001684
cristy3ed852e2009-09-05 21:47:34 +00001685 assert(image != (Image *) NULL);
1686 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001687 assert(image->cache != (Cache) NULL);
1688 cache_info=(CacheInfo *) image->cache;
1689 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001690 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001691 (GetAuthenticPixelsHandler) NULL)
1692 {
cristyacd2ed22011-08-30 01:44:23 +00001693 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1694 exception);
1695 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001696 }
cristy2036f5c2010-09-19 21:18:17 +00001697 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001698 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001699 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001700 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001701}
1702
1703/*
1704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1705% %
1706% %
1707% %
1708+ G e t A u t h e n t i c P i x e l s C a c h e %
1709% %
1710% %
1711% %
1712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1713%
1714% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1715% as defined by the geometry parameters. A pointer to the pixels is returned
1716% if the pixels are transferred, otherwise a NULL is returned.
1717%
1718% The format of the GetAuthenticPixelsCache() method is:
1719%
cristy4c08aed2011-07-01 19:47:50 +00001720% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001721% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001722% ExceptionInfo *exception)
1723%
1724% A description of each parameter follows:
1725%
1726% o image: the image.
1727%
1728% o x,y,columns,rows: These values define the perimeter of a region of
1729% pixels.
1730%
1731% o exception: return any errors or warnings in this structure.
1732%
1733*/
cristy4c08aed2011-07-01 19:47:50 +00001734static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001735 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001736 ExceptionInfo *exception)
1737{
1738 CacheInfo
1739 *cache_info;
1740
cristy5c9e6f22010-09-17 17:31:01 +00001741 const int
1742 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001743
cristy4c08aed2011-07-01 19:47:50 +00001744 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001745 *q;
cristy4c08aed2011-07-01 19:47:50 +00001746
cristye7cc7cf2010-09-21 13:26:47 +00001747 assert(image != (const Image *) NULL);
1748 assert(image->signature == MagickSignature);
1749 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001750 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001751 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001752 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001753 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001754 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001755 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001756 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001757 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001758}
1759
1760/*
1761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762% %
1763% %
1764% %
1765+ G e t I m a g e E x t e n t %
1766% %
1767% %
1768% %
1769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1770%
cristy4c08aed2011-07-01 19:47:50 +00001771% GetImageExtent() returns the extent of the pixels associated corresponding
1772% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001773%
1774% The format of the GetImageExtent() method is:
1775%
1776% MagickSizeType GetImageExtent(const Image *image)
1777%
1778% A description of each parameter follows:
1779%
1780% o image: the image.
1781%
1782*/
1783MagickExport MagickSizeType GetImageExtent(const Image *image)
1784{
1785 CacheInfo
1786 *cache_info;
1787
cristy5c9e6f22010-09-17 17:31:01 +00001788 const int
1789 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001790
cristy3ed852e2009-09-05 21:47:34 +00001791 assert(image != (Image *) NULL);
1792 assert(image->signature == MagickSignature);
1793 if (image->debug != MagickFalse)
1794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1795 assert(image->cache != (Cache) NULL);
1796 cache_info=(CacheInfo *) image->cache;
1797 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001798 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001799 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001800}
1801
1802/*
1803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1804% %
1805% %
1806% %
1807+ G e t I m a g e P i x e l C a c h e %
1808% %
1809% %
1810% %
1811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1812%
1813% GetImagePixelCache() ensures that there is only a single reference to the
1814% pixel cache to be modified, updating the provided cache pointer to point to
1815% a clone of the original pixel cache if necessary.
1816%
1817% The format of the GetImagePixelCache method is:
1818%
1819% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1820% ExceptionInfo *exception)
1821%
1822% A description of each parameter follows:
1823%
1824% o image: the image.
1825%
1826% o clone: any value other than MagickFalse clones the cache pixels.
1827%
1828% o exception: return any errors or warnings in this structure.
1829%
1830*/
cristyaf894d72011-08-06 23:03:10 +00001831
cristyf1832792012-05-08 18:38:18 +00001832static inline MagickBooleanType ValidatePixelCacheMorphology(
1833 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001834{
cristyf1832792012-05-08 18:38:18 +00001835 const CacheInfo
1836 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001837
cristyf1832792012-05-08 18:38:18 +00001838 const PixelChannelMap
1839 *restrict p,
1840 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001841
cristy3ed852e2009-09-05 21:47:34 +00001842 /*
1843 Does the image match the pixel cache morphology?
1844 */
1845 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001846 p=image->channel_map;
1847 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001848 if ((image->storage_class != cache_info->storage_class) ||
1849 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001850 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001851 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001852 (image->columns != cache_info->columns) ||
1853 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001854 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001855 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001856 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001857 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001858 return(MagickFalse);
1859 return(MagickTrue);
1860}
1861
cristycd01fae2011-08-06 23:52:42 +00001862static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1863 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001864{
1865 CacheInfo
1866 *cache_info;
1867
cristy3ed852e2009-09-05 21:47:34 +00001868 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001869 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001870 status;
1871
cristy50a10922010-02-15 18:35:25 +00001872 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001873 cpu_throttle = 0,
1874 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001875 time_limit = 0;
1876
cristy1ea34962010-07-01 19:49:21 +00001877 static time_t
cristy208b1002011-08-07 18:51:50 +00001878 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001879
cristyc4f9f132010-03-04 18:50:01 +00001880 status=MagickTrue;
1881 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001882 if (cpu_throttle == 0)
1883 {
1884 char
1885 *limit;
1886
1887 /*
1888 Set CPU throttle in milleseconds.
1889 */
1890 cpu_throttle=MagickResourceInfinity;
1891 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1892 if (limit == (char *) NULL)
1893 limit=GetPolicyValue("throttle");
1894 if (limit != (char *) NULL)
1895 {
1896 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1897 limit=DestroyString(limit);
1898 }
1899 }
1900 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1901 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001902 if (time_limit == 0)
1903 {
cristy6ebe97c2010-07-03 01:17:28 +00001904 /*
1905 Set the exire time in seconds.
1906 */
cristy1ea34962010-07-01 19:49:21 +00001907 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001908 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001909 }
1910 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001911 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001912 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001913 assert(image->cache != (Cache) NULL);
1914 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001915 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001916 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001917 {
cristyceb55ee2010-11-06 16:05:49 +00001918 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001919 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001920 {
cristyceb55ee2010-11-06 16:05:49 +00001921 Image
1922 clone_image;
1923
1924 CacheInfo
1925 *clone_info;
1926
1927 /*
1928 Clone pixel cache.
1929 */
1930 clone_image=(*image);
1931 clone_image.semaphore=AllocateSemaphoreInfo();
1932 clone_image.reference_count=1;
1933 clone_image.cache=ClonePixelCache(cache_info);
1934 clone_info=(CacheInfo *) clone_image.cache;
1935 status=OpenPixelCache(&clone_image,IOMode,exception);
1936 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001937 {
cristy5a7fbfb2010-11-06 16:10:59 +00001938 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001939 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001940 if (status != MagickFalse)
1941 {
cristy979bf772011-08-08 00:04:15 +00001942 if (cache_info->mode == ReadMode)
1943 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001944 destroy=MagickTrue;
1945 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001946 }
1947 }
cristyceb55ee2010-11-06 16:05:49 +00001948 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001949 }
cristyceb55ee2010-11-06 16:05:49 +00001950 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001951 }
cristy4320e0e2009-09-10 15:00:08 +00001952 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001953 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001954 if (status != MagickFalse)
1955 {
1956 /*
1957 Ensure the image matches the pixel cache morphology.
1958 */
1959 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001960 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001961 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001962 {
1963 status=OpenPixelCache(image,IOMode,exception);
1964 cache_info=(CacheInfo *) image->cache;
1965 if (cache_info->type == DiskCache)
1966 (void) ClosePixelCacheOnDisk(cache_info);
1967 }
cristy3ed852e2009-09-05 21:47:34 +00001968 }
cristyf84a1932010-01-03 18:00:18 +00001969 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001970 if (status == MagickFalse)
1971 return((Cache) NULL);
1972 return(image->cache);
1973}
1974
1975/*
1976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1977% %
1978% %
1979% %
cristyce1fe792012-05-16 15:58:37 +00001980+ G e t I m a g e P i x e l C a c h e T y p e %
1981% %
1982% %
1983% %
1984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985%
1986% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1987% DiskCache, MemoryCache, MapCache, or PingCache.
1988%
1989% The format of the GetImagePixelCacheType() method is:
1990%
cristy5bef4cd2012-05-17 18:08:56 +00001991% CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001992%
1993% A description of each parameter follows:
1994%
1995% o image: the image.
1996%
1997*/
cristy5bef4cd2012-05-17 18:08:56 +00001998MagickExport CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001999{
cristy238287d2012-05-17 18:16:56 +00002000 CacheInfo
2001 *cache_info;
2002
2003 assert(image != (Image *) NULL);
2004 assert(image->signature == MagickSignature);
2005 assert(image->cache != (Cache) NULL);
2006 cache_info=(CacheInfo *) image->cache;
2007 assert(cache_info->signature == MagickSignature);
2008 return(cache_info->type);
cristyce1fe792012-05-16 15:58:37 +00002009}
2010
2011/*
2012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013% %
2014% %
2015% %
cristy3ed852e2009-09-05 21:47:34 +00002016% G e t O n e A u t h e n t i c P i x e l %
2017% %
2018% %
2019% %
2020%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2021%
2022% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2023% location. The image background color is returned if an error occurs.
2024%
2025% The format of the GetOneAuthenticPixel() method is:
2026%
cristybb503372010-05-27 20:51:26 +00002027% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002028% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002029%
2030% A description of each parameter follows:
2031%
2032% o image: the image.
2033%
2034% o x,y: These values define the location of the pixel to return.
2035%
2036% o pixel: return a pixel at the specified (x,y) location.
2037%
2038% o exception: return any errors or warnings in this structure.
2039%
2040*/
cristyacbbb7c2010-06-30 18:56:48 +00002041MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002042 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002043{
2044 CacheInfo
2045 *cache_info;
2046
cristy4c08aed2011-07-01 19:47:50 +00002047 register Quantum
2048 *q;
cristy2036f5c2010-09-19 21:18:17 +00002049
cristy2ed42f62011-10-02 19:49:57 +00002050 register ssize_t
2051 i;
2052
cristy3ed852e2009-09-05 21:47:34 +00002053 assert(image != (Image *) NULL);
2054 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002055 assert(image->cache != (Cache) NULL);
2056 cache_info=(CacheInfo *) image->cache;
2057 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002058 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002059 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2060 (GetOneAuthenticPixelFromHandler) NULL)
2061 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2062 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002063 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2064 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002065 {
cristy9e0719b2011-12-29 03:45:45 +00002066 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2067 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2068 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2069 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2070 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002071 return(MagickFalse);
2072 }
2073 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2074 {
2075 PixelChannel
2076 channel;
2077
cristye2a912b2011-12-05 20:02:07 +00002078 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002079 pixel[channel]=q[i];
2080 }
cristy2036f5c2010-09-19 21:18:17 +00002081 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002082}
2083
2084/*
2085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2086% %
2087% %
2088% %
2089+ 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 %
2090% %
2091% %
2092% %
2093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2094%
2095% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2096% location. The image background color is returned if an error occurs.
2097%
2098% The format of the GetOneAuthenticPixelFromCache() method is:
2099%
2100% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002101% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002102% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002103%
2104% A description of each parameter follows:
2105%
2106% o image: the image.
2107%
2108% o x,y: These values define the location of the pixel to return.
2109%
2110% o pixel: return a pixel at the specified (x,y) location.
2111%
2112% o exception: return any errors or warnings in this structure.
2113%
2114*/
2115static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002116 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002117{
cristy098f78c2010-09-23 17:28:44 +00002118 CacheInfo
2119 *cache_info;
2120
2121 const int
2122 id = GetOpenMPThreadId();
2123
cristy4c08aed2011-07-01 19:47:50 +00002124 register Quantum
2125 *q;
cristy3ed852e2009-09-05 21:47:34 +00002126
cristy2ed42f62011-10-02 19:49:57 +00002127 register ssize_t
2128 i;
2129
cristy0158a4b2010-09-20 13:59:45 +00002130 assert(image != (const Image *) NULL);
2131 assert(image->signature == MagickSignature);
2132 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002133 cache_info=(CacheInfo *) image->cache;
2134 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002135 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002136 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002137 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2138 exception);
2139 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002140 {
cristy9e0719b2011-12-29 03:45:45 +00002141 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2142 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2143 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2144 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2145 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002146 return(MagickFalse);
2147 }
2148 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2149 {
2150 PixelChannel
2151 channel;
2152
cristye2a912b2011-12-05 20:02:07 +00002153 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002154 pixel[channel]=q[i];
2155 }
cristy3ed852e2009-09-05 21:47:34 +00002156 return(MagickTrue);
2157}
2158
2159/*
2160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2161% %
2162% %
2163% %
cristy3ed852e2009-09-05 21:47:34 +00002164% G e t O n e V i r t u a l P i x e l %
2165% %
2166% %
2167% %
2168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2169%
2170% GetOneVirtualPixel() returns a single virtual pixel at the specified
2171% (x,y) location. The image background color is returned if an error occurs.
2172% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2173%
2174% The format of the GetOneVirtualPixel() method is:
2175%
cristybb503372010-05-27 20:51:26 +00002176% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002177% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002178%
2179% A description of each parameter follows:
2180%
2181% o image: the image.
2182%
2183% o x,y: These values define the location of the pixel to return.
2184%
2185% o pixel: return a pixel at the specified (x,y) location.
2186%
2187% o exception: return any errors or warnings in this structure.
2188%
2189*/
2190MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002191 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002192{
cristy3ed852e2009-09-05 21:47:34 +00002193 CacheInfo
2194 *cache_info;
2195
cristy0158a4b2010-09-20 13:59:45 +00002196 const int
2197 id = GetOpenMPThreadId();
2198
cristy4c08aed2011-07-01 19:47:50 +00002199 const Quantum
2200 *p;
cristy2036f5c2010-09-19 21:18:17 +00002201
cristy2ed42f62011-10-02 19:49:57 +00002202 register ssize_t
2203 i;
2204
cristy3ed852e2009-09-05 21:47:34 +00002205 assert(image != (const Image *) NULL);
2206 assert(image->signature == MagickSignature);
2207 assert(image->cache != (Cache) NULL);
2208 cache_info=(CacheInfo *) image->cache;
2209 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002210 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002211 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2212 (GetOneVirtualPixelFromHandler) NULL)
2213 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2214 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002215 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002216 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002217 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002218 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002219 {
cristy9e0719b2011-12-29 03:45:45 +00002220 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2221 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2222 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2223 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2224 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002225 return(MagickFalse);
2226 }
2227 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2228 {
2229 PixelChannel
2230 channel;
2231
cristye2a912b2011-12-05 20:02:07 +00002232 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002233 pixel[channel]=p[i];
2234 }
cristy2036f5c2010-09-19 21:18:17 +00002235 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002236}
2237
2238/*
2239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240% %
2241% %
2242% %
2243+ 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 %
2244% %
2245% %
2246% %
2247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2248%
2249% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2250% specified (x,y) location. The image background color is returned if an
2251% error occurs.
2252%
2253% The format of the GetOneVirtualPixelFromCache() method is:
2254%
2255% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002256% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002257% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002258%
2259% A description of each parameter follows:
2260%
2261% o image: the image.
2262%
2263% o virtual_pixel_method: the virtual pixel method.
2264%
2265% o x,y: These values define the location of the pixel to return.
2266%
2267% o pixel: return a pixel at the specified (x,y) location.
2268%
2269% o exception: return any errors or warnings in this structure.
2270%
2271*/
2272static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002273 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002274 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002275{
cristy0158a4b2010-09-20 13:59:45 +00002276 CacheInfo
2277 *cache_info;
2278
2279 const int
2280 id = GetOpenMPThreadId();
2281
cristy4c08aed2011-07-01 19:47:50 +00002282 const Quantum
2283 *p;
cristy3ed852e2009-09-05 21:47:34 +00002284
cristy2ed42f62011-10-02 19:49:57 +00002285 register ssize_t
2286 i;
2287
cristye7cc7cf2010-09-21 13:26:47 +00002288 assert(image != (const Image *) NULL);
2289 assert(image->signature == MagickSignature);
2290 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002291 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002292 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002293 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002294 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002295 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002296 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002297 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002298 {
cristy9e0719b2011-12-29 03:45:45 +00002299 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2300 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2301 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2302 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2303 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002304 return(MagickFalse);
2305 }
2306 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2307 {
2308 PixelChannel
2309 channel;
2310
cristye2a912b2011-12-05 20:02:07 +00002311 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002312 pixel[channel]=p[i];
2313 }
cristy3ed852e2009-09-05 21:47:34 +00002314 return(MagickTrue);
2315}
2316
2317/*
2318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319% %
2320% %
2321% %
cristy3aa93752011-12-18 15:54:24 +00002322% G e t O n e V i r t u a l P i x e l I n f o %
2323% %
2324% %
2325% %
2326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2327%
2328% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2329% location. The image background color is returned if an error occurs. If
2330% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2331%
2332% The format of the GetOneVirtualPixelInfo() method is:
2333%
2334% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2335% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2336% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2337%
2338% A description of each parameter follows:
2339%
2340% o image: the image.
2341%
2342% o virtual_pixel_method: the virtual pixel method.
2343%
2344% o x,y: these values define the location of the pixel to return.
2345%
2346% o pixel: return a pixel at the specified (x,y) location.
2347%
2348% o exception: return any errors or warnings in this structure.
2349%
2350*/
2351MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2352 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2353 PixelInfo *pixel,ExceptionInfo *exception)
2354{
2355 CacheInfo
2356 *cache_info;
2357
2358 const int
2359 id = GetOpenMPThreadId();
2360
2361 register const Quantum
2362 *p;
2363
2364 assert(image != (const Image *) NULL);
2365 assert(image->signature == MagickSignature);
2366 assert(image->cache != (Cache) NULL);
2367 cache_info=(CacheInfo *) image->cache;
2368 assert(cache_info->signature == MagickSignature);
2369 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002370 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002371 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2372 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002373 if (p == (const Quantum *) NULL)
2374 return(MagickFalse);
2375 GetPixelInfoPixel(image,p,pixel);
2376 return(MagickTrue);
2377}
2378
2379/*
2380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2381% %
2382% %
2383% %
cristy3ed852e2009-09-05 21:47:34 +00002384+ G e t P i x e l C a c h e C o l o r s p a c e %
2385% %
2386% %
2387% %
2388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2389%
2390% GetPixelCacheColorspace() returns the class type of the pixel cache.
2391%
2392% The format of the GetPixelCacheColorspace() method is:
2393%
2394% Colorspace GetPixelCacheColorspace(Cache cache)
2395%
2396% A description of each parameter follows:
2397%
2398% o cache: the pixel cache.
2399%
2400*/
cristya6577ff2011-09-02 19:54:26 +00002401MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002402{
2403 CacheInfo
2404 *cache_info;
2405
2406 assert(cache != (Cache) NULL);
2407 cache_info=(CacheInfo *) cache;
2408 assert(cache_info->signature == MagickSignature);
2409 if (cache_info->debug != MagickFalse)
2410 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2411 cache_info->filename);
2412 return(cache_info->colorspace);
2413}
2414
2415/*
2416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2417% %
2418% %
2419% %
2420+ G e t P i x e l C a c h e M e t h o d s %
2421% %
2422% %
2423% %
2424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2425%
2426% GetPixelCacheMethods() initializes the CacheMethods structure.
2427%
2428% The format of the GetPixelCacheMethods() method is:
2429%
2430% void GetPixelCacheMethods(CacheMethods *cache_methods)
2431%
2432% A description of each parameter follows:
2433%
2434% o cache_methods: Specifies a pointer to a CacheMethods structure.
2435%
2436*/
cristya6577ff2011-09-02 19:54:26 +00002437MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002438{
2439 assert(cache_methods != (CacheMethods *) NULL);
2440 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2441 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2442 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002443 cache_methods->get_virtual_metacontent_from_handler=
2444 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002445 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2446 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002447 cache_methods->get_authentic_metacontent_from_handler=
2448 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002449 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2450 cache_methods->get_one_authentic_pixel_from_handler=
2451 GetOneAuthenticPixelFromCache;
2452 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2453 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2454 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2455}
2456
2457/*
2458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2459% %
2460% %
2461% %
2462+ G e t P i x e l C a c h e N e x u s E x t e n t %
2463% %
2464% %
2465% %
2466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2467%
cristy4c08aed2011-07-01 19:47:50 +00002468% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2469% corresponding with the last call to SetPixelCacheNexusPixels() or
2470% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002471%
2472% The format of the GetPixelCacheNexusExtent() method is:
2473%
2474% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2475% NexusInfo *nexus_info)
2476%
2477% A description of each parameter follows:
2478%
2479% o nexus_info: the nexus info.
2480%
2481*/
cristya6577ff2011-09-02 19:54:26 +00002482MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002483 NexusInfo *nexus_info)
2484{
2485 CacheInfo
2486 *cache_info;
2487
2488 MagickSizeType
2489 extent;
2490
cristy9f027d12011-09-21 01:17:17 +00002491 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002492 cache_info=(CacheInfo *) cache;
2493 assert(cache_info->signature == MagickSignature);
2494 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2495 if (extent == 0)
2496 return((MagickSizeType) cache_info->columns*cache_info->rows);
2497 return(extent);
2498}
2499
2500/*
2501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2502% %
2503% %
2504% %
cristy4c08aed2011-07-01 19:47:50 +00002505+ 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 +00002506% %
2507% %
2508% %
2509%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2510%
cristy4c08aed2011-07-01 19:47:50 +00002511% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2512% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002513%
cristy4c08aed2011-07-01 19:47:50 +00002514% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002515%
cristy4c08aed2011-07-01 19:47:50 +00002516% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002517% NexusInfo *nexus_info)
2518%
2519% A description of each parameter follows:
2520%
2521% o cache: the pixel cache.
2522%
cristy4c08aed2011-07-01 19:47:50 +00002523% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002524%
2525*/
cristya6577ff2011-09-02 19:54:26 +00002526MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002527 NexusInfo *nexus_info)
2528{
2529 CacheInfo
2530 *cache_info;
2531
cristy9f027d12011-09-21 01:17:17 +00002532 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002533 cache_info=(CacheInfo *) cache;
2534 assert(cache_info->signature == MagickSignature);
2535 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002536 return((void *) NULL);
2537 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002538}
2539
2540/*
2541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2542% %
2543% %
2544% %
2545+ G e t P i x e l C a c h e N e x u s P i x e l s %
2546% %
2547% %
2548% %
2549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2550%
2551% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2552% cache nexus.
2553%
2554% The format of the GetPixelCacheNexusPixels() method is:
2555%
cristy4c08aed2011-07-01 19:47:50 +00002556% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002557% NexusInfo *nexus_info)
2558%
2559% A description of each parameter follows:
2560%
2561% o cache: the pixel cache.
2562%
2563% o nexus_info: the cache nexus to return the pixels.
2564%
2565*/
cristya6577ff2011-09-02 19:54:26 +00002566MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002567 NexusInfo *nexus_info)
2568{
2569 CacheInfo
2570 *cache_info;
2571
cristy9f027d12011-09-21 01:17:17 +00002572 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002573 cache_info=(CacheInfo *) cache;
2574 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002575 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002576 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002577 return(nexus_info->pixels);
2578}
2579
2580/*
2581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2582% %
2583% %
2584% %
cristy056ba772010-01-02 23:33:54 +00002585+ G e t P i x e l C a c h e P i x e l s %
2586% %
2587% %
2588% %
2589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2590%
2591% GetPixelCachePixels() returns the pixels associated with the specified image.
2592%
2593% The format of the GetPixelCachePixels() method is:
2594%
cristyf84a1932010-01-03 18:00:18 +00002595% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2596% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002597%
2598% A description of each parameter follows:
2599%
2600% o image: the image.
2601%
2602% o length: the pixel cache length.
2603%
cristyf84a1932010-01-03 18:00:18 +00002604% o exception: return any errors or warnings in this structure.
2605%
cristy056ba772010-01-02 23:33:54 +00002606*/
cristyd1dd6e42011-09-04 01:46:08 +00002607MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002608 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002609{
2610 CacheInfo
2611 *cache_info;
2612
2613 assert(image != (const Image *) NULL);
2614 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002615 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002616 assert(length != (MagickSizeType *) NULL);
2617 assert(exception != (ExceptionInfo *) NULL);
2618 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002619 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002620 assert(cache_info->signature == MagickSignature);
2621 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002622 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002623 return((void *) NULL);
2624 *length=cache_info->length;
2625 return((void *) cache_info->pixels);
2626}
2627
2628/*
2629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630% %
2631% %
2632% %
cristyb32b90a2009-09-07 21:45:48 +00002633+ G e t P i x e l C a c h e S t o r a g e C l a s s %
cristy3ed852e2009-09-05 21:47:34 +00002634% %
2635% %
2636% %
2637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2638%
2639% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2640%
2641% The format of the GetPixelCacheStorageClass() method is:
2642%
2643% ClassType GetPixelCacheStorageClass(Cache cache)
2644%
2645% A description of each parameter follows:
2646%
2647% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2648%
2649% o cache: the pixel cache.
2650%
2651*/
cristya6577ff2011-09-02 19:54:26 +00002652MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002653{
2654 CacheInfo
2655 *cache_info;
2656
2657 assert(cache != (Cache) NULL);
2658 cache_info=(CacheInfo *) cache;
2659 assert(cache_info->signature == MagickSignature);
2660 if (cache_info->debug != MagickFalse)
2661 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2662 cache_info->filename);
2663 return(cache_info->storage_class);
2664}
2665
2666/*
2667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668% %
2669% %
2670% %
cristyb32b90a2009-09-07 21:45:48 +00002671+ G e t P i x e l C a c h e T i l e S i z e %
2672% %
2673% %
2674% %
2675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2676%
2677% GetPixelCacheTileSize() returns the pixel cache tile size.
2678%
2679% The format of the GetPixelCacheTileSize() method is:
2680%
cristybb503372010-05-27 20:51:26 +00002681% void GetPixelCacheTileSize(const Image *image,size_t *width,
2682% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002683%
2684% A description of each parameter follows:
2685%
2686% o image: the image.
2687%
2688% o width: the optimize cache tile width in pixels.
2689%
2690% o height: the optimize cache tile height in pixels.
2691%
2692*/
cristya6577ff2011-09-02 19:54:26 +00002693MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002694 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002695{
cristy4c08aed2011-07-01 19:47:50 +00002696 CacheInfo
2697 *cache_info;
2698
cristyb32b90a2009-09-07 21:45:48 +00002699 assert(image != (Image *) NULL);
2700 assert(image->signature == MagickSignature);
2701 if (image->debug != MagickFalse)
2702 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002703 cache_info=(CacheInfo *) image->cache;
2704 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002705 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristy238287d2012-05-17 18:16:56 +00002706 if (GetImagePixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002707 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002708 *height=(*width);
2709}
2710
2711/*
2712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2713% %
2714% %
2715% %
cristy3ed852e2009-09-05 21:47:34 +00002716+ 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 %
2717% %
2718% %
2719% %
2720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2721%
2722% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2723% pixel cache. A virtual pixel is any pixel access that is outside the
2724% boundaries of the image cache.
2725%
2726% The format of the GetPixelCacheVirtualMethod() method is:
2727%
2728% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2729%
2730% A description of each parameter follows:
2731%
2732% o image: the image.
2733%
2734*/
cristyd1dd6e42011-09-04 01:46:08 +00002735MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002736{
2737 CacheInfo
2738 *cache_info;
2739
2740 assert(image != (Image *) NULL);
2741 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002742 assert(image->cache != (Cache) NULL);
2743 cache_info=(CacheInfo *) image->cache;
2744 assert(cache_info->signature == MagickSignature);
2745 return(cache_info->virtual_pixel_method);
2746}
2747
2748/*
2749%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2750% %
2751% %
2752% %
cristy4c08aed2011-07-01 19:47:50 +00002753+ 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 +00002754% %
2755% %
2756% %
2757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2758%
cristy4c08aed2011-07-01 19:47:50 +00002759% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2760% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002761%
cristy4c08aed2011-07-01 19:47:50 +00002762% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002763%
cristy4c08aed2011-07-01 19:47:50 +00002764% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002765%
2766% A description of each parameter follows:
2767%
2768% o image: the image.
2769%
2770*/
cristy4c08aed2011-07-01 19:47:50 +00002771static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002772{
2773 CacheInfo
2774 *cache_info;
2775
cristy5c9e6f22010-09-17 17:31:01 +00002776 const int
2777 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002778
cristy4c08aed2011-07-01 19:47:50 +00002779 const void
2780 *metacontent;
2781
cristye7cc7cf2010-09-21 13:26:47 +00002782 assert(image != (const Image *) NULL);
2783 assert(image->signature == MagickSignature);
2784 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002785 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002786 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002787 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002788 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2789 cache_info->nexus_info[id]);
2790 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002791}
2792
2793/*
2794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2795% %
2796% %
2797% %
cristy4c08aed2011-07-01 19:47:50 +00002798+ 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 +00002799% %
2800% %
2801% %
2802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2803%
cristy4c08aed2011-07-01 19:47:50 +00002804% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2805% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002806%
cristy4c08aed2011-07-01 19:47:50 +00002807% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002808%
cristy4c08aed2011-07-01 19:47:50 +00002809% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002810% NexusInfo *nexus_info)
2811%
2812% A description of each parameter follows:
2813%
2814% o cache: the pixel cache.
2815%
cristy4c08aed2011-07-01 19:47:50 +00002816% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002817%
2818*/
cristya6577ff2011-09-02 19:54:26 +00002819MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002820 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002821{
2822 CacheInfo
2823 *cache_info;
2824
cristye7cc7cf2010-09-21 13:26:47 +00002825 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002826 cache_info=(CacheInfo *) cache;
2827 assert(cache_info->signature == MagickSignature);
2828 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002829 return((void *) NULL);
2830 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002831}
2832
2833/*
2834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2835% %
2836% %
2837% %
cristy4c08aed2011-07-01 19:47:50 +00002838% 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 +00002839% %
2840% %
2841% %
2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843%
cristy4c08aed2011-07-01 19:47:50 +00002844% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2845% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2846% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002847%
cristy4c08aed2011-07-01 19:47:50 +00002848% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002849%
cristy4c08aed2011-07-01 19:47:50 +00002850% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002851%
2852% A description of each parameter follows:
2853%
2854% o image: the image.
2855%
2856*/
cristy4c08aed2011-07-01 19:47:50 +00002857MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002858{
2859 CacheInfo
2860 *cache_info;
2861
cristy2036f5c2010-09-19 21:18:17 +00002862 const int
2863 id = GetOpenMPThreadId();
2864
cristy4c08aed2011-07-01 19:47:50 +00002865 const void
2866 *metacontent;
2867
cristy3ed852e2009-09-05 21:47:34 +00002868 assert(image != (const Image *) NULL);
2869 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002870 assert(image->cache != (Cache) NULL);
2871 cache_info=(CacheInfo *) image->cache;
2872 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002873 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002874 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002875 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002876 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002877 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2878 cache_info->nexus_info[id]);
2879 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002880}
2881
2882/*
2883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884% %
2885% %
2886% %
2887+ 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 %
2888% %
2889% %
2890% %
2891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2892%
2893% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2894% pixel cache as defined by the geometry parameters. A pointer to the pixels
2895% is returned if the pixels are transferred, otherwise a NULL is returned.
2896%
2897% The format of the GetVirtualPixelsFromNexus() method is:
2898%
cristy4c08aed2011-07-01 19:47:50 +00002899% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002900% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002901% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2902% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002903%
2904% A description of each parameter follows:
2905%
2906% o image: the image.
2907%
2908% o virtual_pixel_method: the virtual pixel method.
2909%
2910% o x,y,columns,rows: These values define the perimeter of a region of
2911% pixels.
2912%
2913% o nexus_info: the cache nexus to acquire.
2914%
2915% o exception: return any errors or warnings in this structure.
2916%
2917*/
2918
cristybb503372010-05-27 20:51:26 +00002919static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002920 DitherMatrix[64] =
2921 {
2922 0, 48, 12, 60, 3, 51, 15, 63,
2923 32, 16, 44, 28, 35, 19, 47, 31,
2924 8, 56, 4, 52, 11, 59, 7, 55,
2925 40, 24, 36, 20, 43, 27, 39, 23,
2926 2, 50, 14, 62, 1, 49, 13, 61,
2927 34, 18, 46, 30, 33, 17, 45, 29,
2928 10, 58, 6, 54, 9, 57, 5, 53,
2929 42, 26, 38, 22, 41, 25, 37, 21
2930 };
2931
cristybb503372010-05-27 20:51:26 +00002932static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002933{
cristybb503372010-05-27 20:51:26 +00002934 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002935 index;
2936
2937 index=x+DitherMatrix[x & 0x07]-32L;
2938 if (index < 0L)
2939 return(0L);
cristybb503372010-05-27 20:51:26 +00002940 if (index >= (ssize_t) columns)
2941 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002942 return(index);
2943}
2944
cristybb503372010-05-27 20:51:26 +00002945static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002946{
cristybb503372010-05-27 20:51:26 +00002947 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002948 index;
2949
2950 index=y+DitherMatrix[y & 0x07]-32L;
2951 if (index < 0L)
2952 return(0L);
cristybb503372010-05-27 20:51:26 +00002953 if (index >= (ssize_t) rows)
2954 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002955 return(index);
2956}
2957
cristybb503372010-05-27 20:51:26 +00002958static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002959{
2960 if (x < 0L)
2961 return(0L);
cristybb503372010-05-27 20:51:26 +00002962 if (x >= (ssize_t) columns)
2963 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002964 return(x);
2965}
2966
cristybb503372010-05-27 20:51:26 +00002967static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002968{
2969 if (y < 0L)
2970 return(0L);
cristybb503372010-05-27 20:51:26 +00002971 if (y >= (ssize_t) rows)
2972 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002973 return(y);
2974}
2975
cristybb503372010-05-27 20:51:26 +00002976static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002977{
cristybb503372010-05-27 20:51:26 +00002978 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002979}
2980
cristybb503372010-05-27 20:51:26 +00002981static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002982{
cristybb503372010-05-27 20:51:26 +00002983 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002984}
2985
cristybb503372010-05-27 20:51:26 +00002986static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2987 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002988{
2989 MagickModulo
2990 modulo;
2991
cristy6162bb42011-07-18 11:34:09 +00002992 /*
2993 Compute the remainder of dividing offset by extent. It returns not only
2994 the quotient (tile the offset falls in) but also the positive remainer
2995 within that tile such that 0 <= remainder < extent. This method is
2996 essentially a ldiv() using a floored modulo division rather than the
2997 normal default truncated modulo division.
2998 */
cristybb503372010-05-27 20:51:26 +00002999 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003000 if (offset < 0L)
3001 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003002 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003003 return(modulo);
3004}
3005
cristya6577ff2011-09-02 19:54:26 +00003006MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003007 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3008 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003009 ExceptionInfo *exception)
3010{
3011 CacheInfo
3012 *cache_info;
3013
3014 MagickOffsetType
3015 offset;
3016
3017 MagickSizeType
3018 length,
3019 number_pixels;
3020
3021 NexusInfo
3022 **virtual_nexus;
3023
cristy4c08aed2011-07-01 19:47:50 +00003024 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003025 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003026 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003027
3028 RectangleInfo
3029 region;
3030
cristy4c08aed2011-07-01 19:47:50 +00003031 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003032 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003033
cristy4c08aed2011-07-01 19:47:50 +00003034 register const void
3035 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003036
cristy4c08aed2011-07-01 19:47:50 +00003037 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003038 *restrict q;
3039
cristybb503372010-05-27 20:51:26 +00003040 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003041 i,
3042 u;
cristy3ed852e2009-09-05 21:47:34 +00003043
cristy4c08aed2011-07-01 19:47:50 +00003044 register unsigned char
3045 *restrict s;
3046
cristy105ba3c2011-07-18 02:28:38 +00003047 ssize_t
3048 v;
3049
cristy4c08aed2011-07-01 19:47:50 +00003050 void
cristy105ba3c2011-07-18 02:28:38 +00003051 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003052
cristy3ed852e2009-09-05 21:47:34 +00003053 /*
3054 Acquire pixels.
3055 */
cristye7cc7cf2010-09-21 13:26:47 +00003056 assert(image != (const Image *) NULL);
3057 assert(image->signature == MagickSignature);
3058 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003059 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003060 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003061 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003062 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003063 region.x=x;
3064 region.y=y;
3065 region.width=columns;
3066 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003067 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003068 if (pixels == (Quantum *) NULL)
3069 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003070 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003071 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3072 nexus_info->region.x;
3073 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3074 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003075 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3076 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003077 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3078 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003079 {
3080 MagickBooleanType
3081 status;
3082
3083 /*
3084 Pixel request is inside cache extents.
3085 */
cristy4c08aed2011-07-01 19:47:50 +00003086 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003087 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003088 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3089 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003090 return((const Quantum *) NULL);
3091 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003092 {
cristy4c08aed2011-07-01 19:47:50 +00003093 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003094 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003095 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003096 }
cristyacd2ed22011-08-30 01:44:23 +00003097 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003098 }
3099 /*
3100 Pixel request is outside cache extents.
3101 */
cristy4c08aed2011-07-01 19:47:50 +00003102 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003103 virtual_nexus=AcquirePixelCacheNexus(1);
3104 if (virtual_nexus == (NexusInfo **) NULL)
3105 {
cristy4c08aed2011-07-01 19:47:50 +00003106 if (virtual_nexus != (NexusInfo **) NULL)
3107 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003108 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003109 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003110 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003111 }
cristy105ba3c2011-07-18 02:28:38 +00003112 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3113 sizeof(*virtual_pixel));
3114 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003115 switch (virtual_pixel_method)
3116 {
cristy4c08aed2011-07-01 19:47:50 +00003117 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003118 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003119 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003121 case MaskVirtualPixelMethod:
3122 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003123 case EdgeVirtualPixelMethod:
3124 case CheckerTileVirtualPixelMethod:
3125 case HorizontalTileVirtualPixelMethod:
3126 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003127 {
cristy4c08aed2011-07-01 19:47:50 +00003128 if (cache_info->metacontent_extent != 0)
3129 {
cristy6162bb42011-07-18 11:34:09 +00003130 /*
3131 Acquire a metacontent buffer.
3132 */
cristya64b85d2011-09-14 01:02:31 +00003133 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003134 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003135 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003136 {
cristy4c08aed2011-07-01 19:47:50 +00003137 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3138 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003139 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003140 return((const Quantum *) NULL);
3141 }
cristy105ba3c2011-07-18 02:28:38 +00003142 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003143 cache_info->metacontent_extent);
3144 }
3145 switch (virtual_pixel_method)
3146 {
3147 case BlackVirtualPixelMethod:
3148 {
cristy30301712011-07-18 15:06:51 +00003149 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3150 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003151 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3152 break;
3153 }
3154 case GrayVirtualPixelMethod:
3155 {
cristy30301712011-07-18 15:06:51 +00003156 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003157 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3158 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003159 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3160 break;
3161 }
3162 case TransparentVirtualPixelMethod:
3163 {
cristy30301712011-07-18 15:06:51 +00003164 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3165 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003166 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3167 break;
3168 }
3169 case MaskVirtualPixelMethod:
3170 case WhiteVirtualPixelMethod:
3171 {
cristy30301712011-07-18 15:06:51 +00003172 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3173 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003174 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3175 break;
3176 }
3177 default:
3178 {
cristy9e0719b2011-12-29 03:45:45 +00003179 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3180 virtual_pixel);
3181 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3182 virtual_pixel);
3183 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3184 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003185 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3186 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003187 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3188 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003189 break;
3190 }
3191 }
cristy3ed852e2009-09-05 21:47:34 +00003192 break;
3193 }
3194 default:
cristy3ed852e2009-09-05 21:47:34 +00003195 break;
cristy3ed852e2009-09-05 21:47:34 +00003196 }
cristybb503372010-05-27 20:51:26 +00003197 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003198 {
cristybb503372010-05-27 20:51:26 +00003199 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003200 {
3201 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003202 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003203 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3204 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003205 {
3206 MagickModulo
3207 x_modulo,
3208 y_modulo;
3209
3210 /*
3211 Transfer a single pixel.
3212 */
3213 length=(MagickSizeType) 1;
3214 switch (virtual_pixel_method)
3215 {
cristy3ed852e2009-09-05 21:47:34 +00003216 default:
3217 {
3218 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003219 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003220 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003221 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003222 break;
3223 }
3224 case RandomVirtualPixelMethod:
3225 {
3226 if (cache_info->random_info == (RandomInfo *) NULL)
3227 cache_info->random_info=AcquireRandomInfo();
3228 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003229 RandomX(cache_info->random_info,cache_info->columns),
3230 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003231 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003232 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003233 break;
3234 }
3235 case DitherVirtualPixelMethod:
3236 {
3237 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003238 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003239 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003240 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003241 break;
3242 }
3243 case TileVirtualPixelMethod:
3244 {
3245 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3246 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3247 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003248 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003249 exception);
cristy4c08aed2011-07-01 19:47:50 +00003250 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003251 break;
3252 }
3253 case MirrorVirtualPixelMethod:
3254 {
3255 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3256 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003257 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003258 x_modulo.remainder-1L;
3259 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3260 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003261 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003262 y_modulo.remainder-1L;
3263 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003264 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003265 exception);
cristy4c08aed2011-07-01 19:47:50 +00003266 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003267 break;
3268 }
3269 case HorizontalTileEdgeVirtualPixelMethod:
3270 {
3271 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3272 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003273 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003274 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003275 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003276 break;
3277 }
3278 case VerticalTileEdgeVirtualPixelMethod:
3279 {
3280 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3281 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003282 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003283 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003284 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3285 break;
3286 }
3287 case BackgroundVirtualPixelMethod:
3288 case BlackVirtualPixelMethod:
3289 case GrayVirtualPixelMethod:
3290 case TransparentVirtualPixelMethod:
3291 case MaskVirtualPixelMethod:
3292 case WhiteVirtualPixelMethod:
3293 {
3294 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003295 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003296 break;
3297 }
3298 case EdgeVirtualPixelMethod:
3299 case CheckerTileVirtualPixelMethod:
3300 {
3301 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3302 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3303 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3304 {
3305 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003306 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003307 break;
3308 }
3309 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3310 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3311 exception);
3312 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3313 break;
3314 }
3315 case HorizontalTileVirtualPixelMethod:
3316 {
3317 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3318 {
3319 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003320 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003321 break;
3322 }
3323 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3324 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3325 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3326 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3327 exception);
3328 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3329 break;
3330 }
3331 case VerticalTileVirtualPixelMethod:
3332 {
3333 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3334 {
3335 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003336 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003337 break;
3338 }
3339 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3340 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3341 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3342 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3343 exception);
3344 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003345 break;
3346 }
3347 }
cristy4c08aed2011-07-01 19:47:50 +00003348 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003349 break;
cristyed231572011-07-14 02:18:59 +00003350 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003351 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003352 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003353 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003354 {
3355 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3356 s+=cache_info->metacontent_extent;
3357 }
cristy3ed852e2009-09-05 21:47:34 +00003358 continue;
3359 }
3360 /*
3361 Transfer a run of pixels.
3362 */
cristy4c08aed2011-07-01 19:47:50 +00003363 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3364 length,1UL,*virtual_nexus,exception);
3365 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003366 break;
cristy4c08aed2011-07-01 19:47:50 +00003367 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003368 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3369 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003370 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003371 {
cristy4c08aed2011-07-01 19:47:50 +00003372 (void) memcpy(s,r,(size_t) length);
3373 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003374 }
3375 }
3376 }
cristy4c08aed2011-07-01 19:47:50 +00003377 /*
3378 Free resources.
3379 */
cristy105ba3c2011-07-18 02:28:38 +00003380 if (virtual_metacontent != (void *) NULL)
3381 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003382 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3383 return(pixels);
3384}
3385
3386/*
3387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3388% %
3389% %
3390% %
3391+ G e t V i r t u a l P i x e l C a c h e %
3392% %
3393% %
3394% %
3395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3396%
3397% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3398% cache as defined by the geometry parameters. A pointer to the pixels
3399% is returned if the pixels are transferred, otherwise a NULL is returned.
3400%
3401% The format of the GetVirtualPixelCache() method is:
3402%
cristy4c08aed2011-07-01 19:47:50 +00003403% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003404% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3405% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003406% ExceptionInfo *exception)
3407%
3408% A description of each parameter follows:
3409%
3410% o image: the image.
3411%
3412% o virtual_pixel_method: the virtual pixel method.
3413%
3414% o x,y,columns,rows: These values define the perimeter of a region of
3415% pixels.
3416%
3417% o exception: return any errors or warnings in this structure.
3418%
3419*/
cristy4c08aed2011-07-01 19:47:50 +00003420static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003421 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3422 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003423{
3424 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003425 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003426
cristy5c9e6f22010-09-17 17:31:01 +00003427 const int
3428 id = GetOpenMPThreadId();
3429
cristy4c08aed2011-07-01 19:47:50 +00003430 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003431 *p;
cristy4c08aed2011-07-01 19:47:50 +00003432
cristye7cc7cf2010-09-21 13:26:47 +00003433 assert(image != (const Image *) NULL);
3434 assert(image->signature == MagickSignature);
3435 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003436 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003437 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003438 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003439 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003440 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003441 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003442}
3443
3444/*
3445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3446% %
3447% %
3448% %
3449% G e t V i r t u a l P i x e l Q u e u e %
3450% %
3451% %
3452% %
3453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3454%
cristy4c08aed2011-07-01 19:47:50 +00003455% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3456% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003457%
3458% The format of the GetVirtualPixelQueue() method is:
3459%
cristy4c08aed2011-07-01 19:47:50 +00003460% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003461%
3462% A description of each parameter follows:
3463%
3464% o image: the image.
3465%
3466*/
cristy4c08aed2011-07-01 19:47:50 +00003467MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003468{
3469 CacheInfo
3470 *cache_info;
3471
cristy2036f5c2010-09-19 21:18:17 +00003472 const int
3473 id = GetOpenMPThreadId();
3474
cristy3ed852e2009-09-05 21:47:34 +00003475 assert(image != (const Image *) NULL);
3476 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003477 assert(image->cache != (Cache) NULL);
3478 cache_info=(CacheInfo *) image->cache;
3479 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003480 if (cache_info->methods.get_virtual_pixels_handler !=
3481 (GetVirtualPixelsHandler) NULL)
3482 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003483 assert(id < (int) cache_info->number_threads);
3484 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003485}
3486
3487/*
3488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3489% %
3490% %
3491% %
3492% G e t V i r t u a l P i x e l s %
3493% %
3494% %
3495% %
3496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3497%
3498% GetVirtualPixels() returns an immutable pixel region. If the
3499% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003500% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003501% copy of the pixels or it may point to the original pixels in memory.
3502% Performance is maximized if the selected region is part of one row, or one
3503% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003504% (without a copy) if the image is in memory, or in a memory-mapped file. The
3505% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003506%
3507% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003508% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3509% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3510% access the meta-content (of type void) corresponding to the the
3511% region.
cristy3ed852e2009-09-05 21:47:34 +00003512%
3513% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3514%
3515% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3516% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3517% GetCacheViewAuthenticPixels() instead.
3518%
3519% The format of the GetVirtualPixels() method is:
3520%
cristy4c08aed2011-07-01 19:47:50 +00003521% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003522% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003523% ExceptionInfo *exception)
3524%
3525% A description of each parameter follows:
3526%
3527% o image: the image.
3528%
3529% o x,y,columns,rows: These values define the perimeter of a region of
3530% pixels.
3531%
3532% o exception: return any errors or warnings in this structure.
3533%
3534*/
cristy4c08aed2011-07-01 19:47:50 +00003535MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003536 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3537 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003538{
3539 CacheInfo
3540 *cache_info;
3541
cristy2036f5c2010-09-19 21:18:17 +00003542 const int
3543 id = GetOpenMPThreadId();
3544
cristy4c08aed2011-07-01 19:47:50 +00003545 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003546 *p;
cristy4c08aed2011-07-01 19:47:50 +00003547
cristy3ed852e2009-09-05 21:47:34 +00003548 assert(image != (const Image *) NULL);
3549 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003550 assert(image->cache != (Cache) NULL);
3551 cache_info=(CacheInfo *) image->cache;
3552 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003553 if (cache_info->methods.get_virtual_pixel_handler !=
3554 (GetVirtualPixelHandler) NULL)
3555 return(cache_info->methods.get_virtual_pixel_handler(image,
3556 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003557 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003558 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003559 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003560 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003561}
3562
3563/*
3564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3565% %
3566% %
3567% %
3568+ 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 %
3569% %
3570% %
3571% %
3572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3573%
cristy4c08aed2011-07-01 19:47:50 +00003574% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3575% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003576%
3577% The format of the GetVirtualPixelsCache() method is:
3578%
cristy4c08aed2011-07-01 19:47:50 +00003579% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003580%
3581% A description of each parameter follows:
3582%
3583% o image: the image.
3584%
3585*/
cristy4c08aed2011-07-01 19:47:50 +00003586static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003587{
3588 CacheInfo
3589 *cache_info;
3590
cristy5c9e6f22010-09-17 17:31:01 +00003591 const int
3592 id = GetOpenMPThreadId();
3593
cristye7cc7cf2010-09-21 13:26:47 +00003594 assert(image != (const Image *) NULL);
3595 assert(image->signature == MagickSignature);
3596 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003597 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003598 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003599 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003600 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003601}
3602
3603/*
3604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605% %
3606% %
3607% %
3608+ G e t V i r t u a l P i x e l s N e x u s %
3609% %
3610% %
3611% %
3612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613%
3614% GetVirtualPixelsNexus() returns the pixels associated with the specified
3615% cache nexus.
3616%
3617% The format of the GetVirtualPixelsNexus() method is:
3618%
cristy4c08aed2011-07-01 19:47:50 +00003619% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003620% NexusInfo *nexus_info)
3621%
3622% A description of each parameter follows:
3623%
3624% o cache: the pixel cache.
3625%
3626% o nexus_info: the cache nexus to return the colormap pixels.
3627%
3628*/
cristya6577ff2011-09-02 19:54:26 +00003629MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003630 NexusInfo *nexus_info)
3631{
3632 CacheInfo
3633 *cache_info;
3634
cristye7cc7cf2010-09-21 13:26:47 +00003635 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003636 cache_info=(CacheInfo *) cache;
3637 assert(cache_info->signature == MagickSignature);
3638 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003639 return((Quantum *) NULL);
3640 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003641}
3642
3643/*
3644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3645% %
3646% %
3647% %
cristy3ed852e2009-09-05 21:47:34 +00003648+ O p e n P i x e l C a c h e %
3649% %
3650% %
3651% %
3652%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3653%
3654% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3655% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003656% metacontent, and memory mapping the cache if it is disk based. The cache
3657% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003658%
3659% The format of the OpenPixelCache() method is:
3660%
3661% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3662% ExceptionInfo *exception)
3663%
3664% A description of each parameter follows:
3665%
3666% o image: the image.
3667%
3668% o mode: ReadMode, WriteMode, or IOMode.
3669%
3670% o exception: return any errors or warnings in this structure.
3671%
3672*/
3673
cristyd43a46b2010-01-21 02:13:41 +00003674static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003675{
3676 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003677 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003678 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003679 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003680 {
3681 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003682 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003683 cache_info->length);
3684 }
3685}
3686
3687static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3688{
3689 CacheInfo
3690 *cache_info;
3691
3692 MagickOffsetType
3693 count,
3694 extent,
3695 offset;
3696
3697 cache_info=(CacheInfo *) image->cache;
3698 if (image->debug != MagickFalse)
3699 {
3700 char
3701 format[MaxTextExtent],
3702 message[MaxTextExtent];
3703
cristyb9080c92009-12-01 20:13:26 +00003704 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003705 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003706 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003707 cache_info->cache_filename,cache_info->file,format);
3708 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3709 }
3710 if (length != (MagickSizeType) ((MagickOffsetType) length))
3711 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003712 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003713 if (extent < 0)
3714 return(MagickFalse);
3715 if ((MagickSizeType) extent >= length)
3716 return(MagickTrue);
3717 offset=(MagickOffsetType) length-1;
3718 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3719 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3720}
3721
3722static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3723 ExceptionInfo *exception)
3724{
cristy3ed852e2009-09-05 21:47:34 +00003725 CacheInfo
3726 *cache_info,
3727 source_info;
3728
cristyf3a6a9d2010-11-07 21:02:56 +00003729 char
3730 format[MaxTextExtent],
3731 message[MaxTextExtent];
3732
cristy4c08aed2011-07-01 19:47:50 +00003733 MagickBooleanType
3734 status;
3735
cristy3ed852e2009-09-05 21:47:34 +00003736 MagickSizeType
3737 length,
3738 number_pixels;
3739
cristy3ed852e2009-09-05 21:47:34 +00003740 size_t
cristye076a6e2010-08-15 19:59:43 +00003741 columns,
cristy3ed852e2009-09-05 21:47:34 +00003742 packet_size;
3743
cristye7cc7cf2010-09-21 13:26:47 +00003744 assert(image != (const Image *) NULL);
3745 assert(image->signature == MagickSignature);
3746 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003747 if (image->debug != MagickFalse)
3748 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3749 if ((image->columns == 0) || (image->rows == 0))
3750 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3751 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003752 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003753 source_info=(*cache_info);
3754 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003755 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003756 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003757 cache_info->storage_class=image->storage_class;
3758 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003759 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003760 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003761 cache_info->rows=image->rows;
3762 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003763 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003764 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003765 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3766 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003767 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003768 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003769 if (image->ping != MagickFalse)
3770 {
cristy73724512010-04-12 14:43:14 +00003771 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003772 cache_info->pixels=(Quantum *) NULL;
3773 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003774 cache_info->length=0;
3775 return(MagickTrue);
3776 }
cristy3ed852e2009-09-05 21:47:34 +00003777 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003778 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003779 if (image->metacontent_extent != 0)
3780 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003781 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003782 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003783 if (cache_info->columns != columns)
3784 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3785 image->filename);
3786 cache_info->length=length;
3787 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003788 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003789 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003790 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3791 {
3792 status=AcquireMagickResource(MemoryResource,cache_info->length);
3793 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3794 (cache_info->type == MemoryCache))
3795 {
cristyd43a46b2010-01-21 02:13:41 +00003796 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003797 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003798 cache_info->pixels=source_info.pixels;
3799 else
3800 {
3801 /*
3802 Create memory pixel cache.
3803 */
cristy4c08aed2011-07-01 19:47:50 +00003804 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003805 if (image->debug != MagickFalse)
3806 {
cristy32cacff2011-12-31 03:36:27 +00003807 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003808 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003809 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3810 cache_info->filename,cache_info->mapped != MagickFalse ?
3811 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003812 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003813 format);
cristy3ed852e2009-09-05 21:47:34 +00003814 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3815 message);
3816 }
cristy3ed852e2009-09-05 21:47:34 +00003817 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003818 cache_info->metacontent=(void *) NULL;
3819 if (cache_info->metacontent_extent != 0)
3820 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003821 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003822 if ((source_info.storage_class != UndefinedClass) &&
3823 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003824 {
cristy4c08aed2011-07-01 19:47:50 +00003825 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003826 exception);
3827 RelinquishPixelCachePixels(&source_info);
3828 }
cristy4c08aed2011-07-01 19:47:50 +00003829 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003830 }
3831 }
3832 RelinquishMagickResource(MemoryResource,cache_info->length);
3833 }
3834 /*
3835 Create pixel cache on disk.
3836 */
3837 status=AcquireMagickResource(DiskResource,cache_info->length);
3838 if (status == MagickFalse)
3839 {
3840 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003841 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003842 return(MagickFalse);
3843 }
cristy413f1302012-01-01 17:48:27 +00003844 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3845 {
3846 (void) ClosePixelCacheOnDisk(cache_info);
3847 *cache_info->cache_filename='\0';
3848 }
cristy3ed852e2009-09-05 21:47:34 +00003849 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3850 {
3851 RelinquishMagickResource(DiskResource,cache_info->length);
3852 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3853 image->filename);
3854 return(MagickFalse);
3855 }
3856 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3857 cache_info->length);
3858 if (status == MagickFalse)
3859 {
3860 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3861 image->filename);
3862 return(MagickFalse);
3863 }
cristyed231572011-07-14 02:18:59 +00003864 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003865 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003866 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003867 cache_info->type=DiskCache;
3868 else
3869 {
3870 status=AcquireMagickResource(MapResource,cache_info->length);
3871 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3872 (cache_info->type != MemoryCache))
3873 cache_info->type=DiskCache;
3874 else
3875 {
cristy4c08aed2011-07-01 19:47:50 +00003876 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003877 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003878 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003879 {
cristy3ed852e2009-09-05 21:47:34 +00003880 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003881 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003882 }
3883 else
3884 {
3885 /*
3886 Create file-backed memory-mapped pixel cache.
3887 */
cristy4c08aed2011-07-01 19:47:50 +00003888 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003889 (void) ClosePixelCacheOnDisk(cache_info);
3890 cache_info->type=MapCache;
3891 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003892 cache_info->metacontent=(void *) NULL;
3893 if (cache_info->metacontent_extent != 0)
3894 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003895 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003896 if ((source_info.storage_class != UndefinedClass) &&
3897 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003898 {
3899 status=ClonePixelCachePixels(cache_info,&source_info,
3900 exception);
3901 RelinquishPixelCachePixels(&source_info);
3902 }
3903 if (image->debug != MagickFalse)
3904 {
cristy413f1302012-01-01 17:48:27 +00003905 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003906 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003907 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003908 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003909 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003910 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003911 format);
cristy3ed852e2009-09-05 21:47:34 +00003912 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3913 message);
3914 }
cristy4c08aed2011-07-01 19:47:50 +00003915 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003916 }
3917 }
3918 RelinquishMagickResource(MapResource,cache_info->length);
3919 }
cristy4c08aed2011-07-01 19:47:50 +00003920 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003921 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003922 {
3923 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3924 RelinquishPixelCachePixels(&source_info);
3925 }
3926 if (image->debug != MagickFalse)
3927 {
cristyb9080c92009-12-01 20:13:26 +00003928 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003929 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003930 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003931 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003932 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003933 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003934 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3935 }
cristy4c08aed2011-07-01 19:47:50 +00003936 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003937}
3938
3939/*
3940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3941% %
3942% %
3943% %
3944+ P e r s i s t P i x e l C a c h e %
3945% %
3946% %
3947% %
3948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3949%
3950% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3951% persistent pixel cache is one that resides on disk and is not destroyed
3952% when the program exits.
3953%
3954% The format of the PersistPixelCache() method is:
3955%
3956% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3957% const MagickBooleanType attach,MagickOffsetType *offset,
3958% ExceptionInfo *exception)
3959%
3960% A description of each parameter follows:
3961%
3962% o image: the image.
3963%
3964% o filename: the persistent pixel cache filename.
3965%
cristyf3a6a9d2010-11-07 21:02:56 +00003966% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003967%
cristy3ed852e2009-09-05 21:47:34 +00003968% o initialize: A value other than zero initializes the persistent pixel
3969% cache.
3970%
3971% o offset: the offset in the persistent cache to store pixels.
3972%
3973% o exception: return any errors or warnings in this structure.
3974%
3975*/
3976MagickExport MagickBooleanType PersistPixelCache(Image *image,
3977 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3978 ExceptionInfo *exception)
3979{
3980 CacheInfo
3981 *cache_info,
3982 *clone_info;
3983
3984 Image
3985 clone_image;
3986
cristy3ed852e2009-09-05 21:47:34 +00003987 MagickBooleanType
3988 status;
3989
cristye076a6e2010-08-15 19:59:43 +00003990 ssize_t
3991 page_size;
3992
cristy3ed852e2009-09-05 21:47:34 +00003993 assert(image != (Image *) NULL);
3994 assert(image->signature == MagickSignature);
3995 if (image->debug != MagickFalse)
3996 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3997 assert(image->cache != (void *) NULL);
3998 assert(filename != (const char *) NULL);
3999 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004000 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004001 cache_info=(CacheInfo *) image->cache;
4002 assert(cache_info->signature == MagickSignature);
4003 if (attach != MagickFalse)
4004 {
4005 /*
cristy01b7eb02009-09-10 23:10:14 +00004006 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004007 */
4008 if (image->debug != MagickFalse)
4009 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004010 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004011 (void) CopyMagickString(cache_info->cache_filename,filename,
4012 MaxTextExtent);
4013 cache_info->type=DiskCache;
4014 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004015 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004016 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004017 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004018 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004019 }
cristy01b7eb02009-09-10 23:10:14 +00004020 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4021 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004022 {
cristyf84a1932010-01-03 18:00:18 +00004023 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004024 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004025 (cache_info->reference_count == 1))
4026 {
4027 int
4028 status;
4029
4030 /*
cristy01b7eb02009-09-10 23:10:14 +00004031 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004032 */
cristy320684d2011-09-23 14:55:47 +00004033 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004034 if (status == 0)
4035 {
4036 (void) CopyMagickString(cache_info->cache_filename,filename,
4037 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004038 *offset+=cache_info->length+page_size-(cache_info->length %
4039 page_size);
cristyf84a1932010-01-03 18:00:18 +00004040 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004041 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004042 if (image->debug != MagickFalse)
4043 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4044 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004045 return(MagickTrue);
4046 }
4047 }
cristyf84a1932010-01-03 18:00:18 +00004048 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004049 }
4050 /*
cristy01b7eb02009-09-10 23:10:14 +00004051 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004052 */
4053 clone_image=(*image);
4054 clone_info=(CacheInfo *) clone_image.cache;
4055 image->cache=ClonePixelCache(cache_info);
4056 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4057 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4058 cache_info->type=DiskCache;
4059 cache_info->offset=(*offset);
4060 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004061 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004062 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004063 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004064 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004065 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4066 return(status);
4067}
4068
4069/*
4070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4071% %
4072% %
4073% %
cristyc11dace2012-01-24 16:39:46 +00004074+ 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 +00004075% %
4076% %
4077% %
4078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4079%
cristyc11dace2012-01-24 16:39:46 +00004080% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4081% defined by the region rectangle and returns a pointer to the region. This
4082% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004083% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4084% pixels are transferred, otherwise a NULL is returned.
4085%
cristyc11dace2012-01-24 16:39:46 +00004086% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004087%
cristyc11dace2012-01-24 16:39:46 +00004088% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004089% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004090% const MagickBooleanType clone,NexusInfo *nexus_info,
4091% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004092%
4093% A description of each parameter follows:
4094%
4095% o image: the image.
4096%
4097% o x,y,columns,rows: These values define the perimeter of a region of
4098% pixels.
4099%
4100% o nexus_info: the cache nexus to set.
4101%
cristy65dbf172011-10-06 17:32:04 +00004102% o clone: clone the pixel cache.
4103%
cristy3ed852e2009-09-05 21:47:34 +00004104% o exception: return any errors or warnings in this structure.
4105%
4106*/
cristyc11dace2012-01-24 16:39:46 +00004107MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4108 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004109 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004110{
4111 CacheInfo
4112 *cache_info;
4113
4114 MagickOffsetType
4115 offset;
4116
4117 MagickSizeType
4118 number_pixels;
4119
4120 RectangleInfo
4121 region;
4122
4123 /*
4124 Validate pixel cache geometry.
4125 */
cristye7cc7cf2010-09-21 13:26:47 +00004126 assert(image != (const Image *) NULL);
4127 assert(image->signature == MagickSignature);
4128 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004129 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004130 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004131 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004132 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004133 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4134 {
4135 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004136 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004137 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004138 }
cristybb503372010-05-27 20:51:26 +00004139 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4140 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004141 {
4142 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004143 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004144 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004145 }
4146 offset=(MagickOffsetType) y*cache_info->columns+x;
4147 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004148 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004149 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4150 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4151 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004152 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004153 /*
4154 Return pixel cache.
4155 */
4156 region.x=x;
4157 region.y=y;
4158 region.width=columns;
4159 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004160 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004161}
4162
4163/*
4164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4165% %
4166% %
4167% %
4168+ 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 %
4169% %
4170% %
4171% %
4172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4173%
4174% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4175% defined by the region rectangle and returns a pointer to the region. This
4176% region is subsequently transferred from the pixel cache with
4177% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4178% pixels are transferred, otherwise a NULL is returned.
4179%
4180% The format of the QueueAuthenticPixelsCache() method is:
4181%
cristy4c08aed2011-07-01 19:47:50 +00004182% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004183% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004184% ExceptionInfo *exception)
4185%
4186% A description of each parameter follows:
4187%
4188% o image: the image.
4189%
4190% o x,y,columns,rows: These values define the perimeter of a region of
4191% pixels.
4192%
4193% o exception: return any errors or warnings in this structure.
4194%
4195*/
cristy4c08aed2011-07-01 19:47:50 +00004196static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004197 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004198 ExceptionInfo *exception)
4199{
4200 CacheInfo
4201 *cache_info;
4202
cristy5c9e6f22010-09-17 17:31:01 +00004203 const int
4204 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004205
cristy4c08aed2011-07-01 19:47:50 +00004206 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004207 *q;
cristy4c08aed2011-07-01 19:47:50 +00004208
cristye7cc7cf2010-09-21 13:26:47 +00004209 assert(image != (const Image *) NULL);
4210 assert(image->signature == MagickSignature);
4211 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004212 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004213 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004214 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004215 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004216 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004217 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004218}
4219
4220/*
4221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4222% %
4223% %
4224% %
4225% Q u e u e A u t h e n t i c P i x e l s %
4226% %
4227% %
4228% %
4229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4230%
4231% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004232% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004233% region is returned, otherwise NULL is returned. The returned pointer may
4234% point to a temporary working buffer for the pixels or it may point to the
4235% final location of the pixels in memory.
4236%
4237% Write-only access means that any existing pixel values corresponding to
4238% the region are ignored. This is useful if the initial image is being
4239% created from scratch, or if the existing pixel values are to be
4240% completely replaced without need to refer to their pre-existing values.
4241% The application is free to read and write the pixel buffer returned by
4242% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4243% initialize the pixel array values. Initializing pixel array values is the
4244% application's responsibility.
4245%
4246% Performance is maximized if the selected region is part of one row, or
4247% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004248% pixels in-place (without a copy) if the image is in memory, or in a
4249% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004250% by the user.
4251%
4252% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004253% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4254% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4255% obtain the meta-content (of type void) corresponding to the region.
4256% Once the Quantum (and/or Quantum) array has been updated, the
4257% changes must be saved back to the underlying image using
4258% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004259%
4260% The format of the QueueAuthenticPixels() method is:
4261%
cristy4c08aed2011-07-01 19:47:50 +00004262% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004263% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004264% ExceptionInfo *exception)
4265%
4266% A description of each parameter follows:
4267%
4268% o image: the image.
4269%
4270% o x,y,columns,rows: These values define the perimeter of a region of
4271% pixels.
4272%
4273% o exception: return any errors or warnings in this structure.
4274%
4275*/
cristy4c08aed2011-07-01 19:47:50 +00004276MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004277 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004278 ExceptionInfo *exception)
4279{
4280 CacheInfo
4281 *cache_info;
4282
cristy2036f5c2010-09-19 21:18:17 +00004283 const int
4284 id = GetOpenMPThreadId();
4285
cristy4c08aed2011-07-01 19:47:50 +00004286 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004287 *q;
cristy4c08aed2011-07-01 19:47:50 +00004288
cristy3ed852e2009-09-05 21:47:34 +00004289 assert(image != (Image *) NULL);
4290 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004291 assert(image->cache != (Cache) NULL);
4292 cache_info=(CacheInfo *) image->cache;
4293 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004294 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004295 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004296 {
cristyc36c8822012-02-14 14:02:36 +00004297 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4298 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004299 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004300 }
cristy2036f5c2010-09-19 21:18:17 +00004301 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004302 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004303 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004304 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004305}
4306
4307/*
4308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4309% %
4310% %
4311% %
cristy4c08aed2011-07-01 19:47:50 +00004312+ 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 +00004313% %
4314% %
4315% %
4316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4317%
cristy4c08aed2011-07-01 19:47:50 +00004318% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004319% the pixel cache.
4320%
cristy4c08aed2011-07-01 19:47:50 +00004321% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004322%
cristy4c08aed2011-07-01 19:47:50 +00004323% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004324% NexusInfo *nexus_info,ExceptionInfo *exception)
4325%
4326% A description of each parameter follows:
4327%
4328% o cache_info: the pixel cache.
4329%
cristy4c08aed2011-07-01 19:47:50 +00004330% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004331%
4332% o exception: return any errors or warnings in this structure.
4333%
4334*/
cristy4c08aed2011-07-01 19:47:50 +00004335static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004336 NexusInfo *nexus_info,ExceptionInfo *exception)
4337{
4338 MagickOffsetType
4339 count,
4340 offset;
4341
4342 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004343 extent,
4344 length;
cristy3ed852e2009-09-05 21:47:34 +00004345
cristybb503372010-05-27 20:51:26 +00004346 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004347 y;
4348
cristy4c08aed2011-07-01 19:47:50 +00004349 register unsigned char
4350 *restrict q;
4351
cristybb503372010-05-27 20:51:26 +00004352 size_t
cristy3ed852e2009-09-05 21:47:34 +00004353 rows;
4354
cristy4c08aed2011-07-01 19:47:50 +00004355 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004356 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004357 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004358 return(MagickTrue);
4359 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4360 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004361 length=(MagickSizeType) nexus_info->region.width*
4362 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004363 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004364 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004365 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004366 switch (cache_info->type)
4367 {
4368 case MemoryCache:
4369 case MapCache:
4370 {
cristy4c08aed2011-07-01 19:47:50 +00004371 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004372 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004373
4374 /*
cristy4c08aed2011-07-01 19:47:50 +00004375 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004376 */
cristydd341db2010-03-04 19:06:38 +00004377 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004378 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004379 {
cristy48078b12010-09-23 17:11:01 +00004380 length=extent;
cristydd341db2010-03-04 19:06:38 +00004381 rows=1UL;
4382 }
cristy4c08aed2011-07-01 19:47:50 +00004383 p=(unsigned char *) cache_info->metacontent+offset*
4384 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004385 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004386 {
cristy8f036fe2010-09-18 02:02:00 +00004387 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004388 p+=cache_info->metacontent_extent*cache_info->columns;
4389 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004390 }
4391 break;
4392 }
4393 case DiskCache:
4394 {
4395 /*
cristy4c08aed2011-07-01 19:47:50 +00004396 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004397 */
4398 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4399 {
4400 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4401 cache_info->cache_filename);
4402 return(MagickFalse);
4403 }
cristydd341db2010-03-04 19:06:38 +00004404 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004405 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004406 {
cristy48078b12010-09-23 17:11:01 +00004407 length=extent;
cristydd341db2010-03-04 19:06:38 +00004408 rows=1UL;
4409 }
cristy48078b12010-09-23 17:11:01 +00004410 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004411 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004412 {
cristy48078b12010-09-23 17:11:01 +00004413 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004414 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004415 cache_info->metacontent_extent,length,(unsigned char *) q);
4416 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004417 break;
4418 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004419 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004420 }
cristyc11dace2012-01-24 16:39:46 +00004421 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4422 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004423 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004424 {
4425 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4426 cache_info->cache_filename);
4427 return(MagickFalse);
4428 }
4429 break;
4430 }
4431 default:
4432 break;
4433 }
4434 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004435 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004436 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004437 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004438 nexus_info->region.width,(double) nexus_info->region.height,(double)
4439 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004440 return(MagickTrue);
4441}
4442
4443/*
4444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4445% %
4446% %
4447% %
4448+ R e a d P i x e l C a c h e P i x e l s %
4449% %
4450% %
4451% %
4452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4453%
4454% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4455% cache.
4456%
4457% The format of the ReadPixelCachePixels() method is:
4458%
4459% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4460% NexusInfo *nexus_info,ExceptionInfo *exception)
4461%
4462% A description of each parameter follows:
4463%
4464% o cache_info: the pixel cache.
4465%
4466% o nexus_info: the cache nexus to read the pixels.
4467%
4468% o exception: return any errors or warnings in this structure.
4469%
4470*/
4471static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4472 NexusInfo *nexus_info,ExceptionInfo *exception)
4473{
4474 MagickOffsetType
4475 count,
4476 offset;
4477
4478 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004479 extent,
4480 length;
cristy3ed852e2009-09-05 21:47:34 +00004481
cristy4c08aed2011-07-01 19:47:50 +00004482 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004483 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004484
cristye076a6e2010-08-15 19:59:43 +00004485 register ssize_t
4486 y;
4487
cristybb503372010-05-27 20:51:26 +00004488 size_t
cristy3ed852e2009-09-05 21:47:34 +00004489 rows;
4490
cristy4c08aed2011-07-01 19:47:50 +00004491 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004492 return(MagickTrue);
4493 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4494 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004495 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004496 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004497 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004498 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004499 q=nexus_info->pixels;
4500 switch (cache_info->type)
4501 {
4502 case MemoryCache:
4503 case MapCache:
4504 {
cristy4c08aed2011-07-01 19:47:50 +00004505 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004506 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004507
4508 /*
4509 Read pixels from memory.
4510 */
cristydd341db2010-03-04 19:06:38 +00004511 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004512 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004513 {
cristy48078b12010-09-23 17:11:01 +00004514 length=extent;
cristydd341db2010-03-04 19:06:38 +00004515 rows=1UL;
4516 }
cristyed231572011-07-14 02:18:59 +00004517 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004518 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004519 {
cristy8f036fe2010-09-18 02:02:00 +00004520 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004521 p+=cache_info->number_channels*cache_info->columns;
4522 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004523 }
4524 break;
4525 }
4526 case DiskCache:
4527 {
4528 /*
4529 Read pixels from disk.
4530 */
4531 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4532 {
4533 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4534 cache_info->cache_filename);
4535 return(MagickFalse);
4536 }
cristydd341db2010-03-04 19:06:38 +00004537 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004538 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004539 {
cristy48078b12010-09-23 17:11:01 +00004540 length=extent;
cristydd341db2010-03-04 19:06:38 +00004541 rows=1UL;
4542 }
cristybb503372010-05-27 20:51:26 +00004543 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004544 {
4545 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004546 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004547 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004548 break;
4549 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004550 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004551 }
cristyc11dace2012-01-24 16:39:46 +00004552 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4553 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004554 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004555 {
4556 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4557 cache_info->cache_filename);
4558 return(MagickFalse);
4559 }
4560 break;
4561 }
4562 default:
4563 break;
4564 }
4565 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004566 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004567 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004568 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004569 nexus_info->region.width,(double) nexus_info->region.height,(double)
4570 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004571 return(MagickTrue);
4572}
4573
4574/*
4575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4576% %
4577% %
4578% %
4579+ R e f e r e n c e P i x e l C a c h e %
4580% %
4581% %
4582% %
4583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4584%
4585% ReferencePixelCache() increments the reference count associated with the
4586% pixel cache returning a pointer to the cache.
4587%
4588% The format of the ReferencePixelCache method is:
4589%
4590% Cache ReferencePixelCache(Cache cache_info)
4591%
4592% A description of each parameter follows:
4593%
4594% o cache_info: the pixel cache.
4595%
4596*/
cristya6577ff2011-09-02 19:54:26 +00004597MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004598{
4599 CacheInfo
4600 *cache_info;
4601
4602 assert(cache != (Cache *) NULL);
4603 cache_info=(CacheInfo *) cache;
4604 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004605 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004606 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004607 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004608 return(cache_info);
4609}
4610
4611/*
4612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4613% %
4614% %
4615% %
4616+ S e t P i x e l C a c h e M e t h o d s %
4617% %
4618% %
4619% %
4620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4621%
4622% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4623%
4624% The format of the SetPixelCacheMethods() method is:
4625%
4626% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4627%
4628% A description of each parameter follows:
4629%
4630% o cache: the pixel cache.
4631%
4632% o cache_methods: Specifies a pointer to a CacheMethods structure.
4633%
4634*/
cristya6577ff2011-09-02 19:54:26 +00004635MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004636{
4637 CacheInfo
4638 *cache_info;
4639
4640 GetOneAuthenticPixelFromHandler
4641 get_one_authentic_pixel_from_handler;
4642
4643 GetOneVirtualPixelFromHandler
4644 get_one_virtual_pixel_from_handler;
4645
4646 /*
4647 Set cache pixel methods.
4648 */
4649 assert(cache != (Cache) NULL);
4650 assert(cache_methods != (CacheMethods *) NULL);
4651 cache_info=(CacheInfo *) cache;
4652 assert(cache_info->signature == MagickSignature);
4653 if (cache_info->debug != MagickFalse)
4654 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4655 cache_info->filename);
4656 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4657 cache_info->methods.get_virtual_pixel_handler=
4658 cache_methods->get_virtual_pixel_handler;
4659 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4660 cache_info->methods.destroy_pixel_handler=
4661 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004662 if (cache_methods->get_virtual_metacontent_from_handler !=
4663 (GetVirtualMetacontentFromHandler) NULL)
4664 cache_info->methods.get_virtual_metacontent_from_handler=
4665 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004666 if (cache_methods->get_authentic_pixels_handler !=
4667 (GetAuthenticPixelsHandler) NULL)
4668 cache_info->methods.get_authentic_pixels_handler=
4669 cache_methods->get_authentic_pixels_handler;
4670 if (cache_methods->queue_authentic_pixels_handler !=
4671 (QueueAuthenticPixelsHandler) NULL)
4672 cache_info->methods.queue_authentic_pixels_handler=
4673 cache_methods->queue_authentic_pixels_handler;
4674 if (cache_methods->sync_authentic_pixels_handler !=
4675 (SyncAuthenticPixelsHandler) NULL)
4676 cache_info->methods.sync_authentic_pixels_handler=
4677 cache_methods->sync_authentic_pixels_handler;
4678 if (cache_methods->get_authentic_pixels_from_handler !=
4679 (GetAuthenticPixelsFromHandler) NULL)
4680 cache_info->methods.get_authentic_pixels_from_handler=
4681 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004682 if (cache_methods->get_authentic_metacontent_from_handler !=
4683 (GetAuthenticMetacontentFromHandler) NULL)
4684 cache_info->methods.get_authentic_metacontent_from_handler=
4685 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004686 get_one_virtual_pixel_from_handler=
4687 cache_info->methods.get_one_virtual_pixel_from_handler;
4688 if (get_one_virtual_pixel_from_handler !=
4689 (GetOneVirtualPixelFromHandler) NULL)
4690 cache_info->methods.get_one_virtual_pixel_from_handler=
4691 cache_methods->get_one_virtual_pixel_from_handler;
4692 get_one_authentic_pixel_from_handler=
4693 cache_methods->get_one_authentic_pixel_from_handler;
4694 if (get_one_authentic_pixel_from_handler !=
4695 (GetOneAuthenticPixelFromHandler) NULL)
4696 cache_info->methods.get_one_authentic_pixel_from_handler=
4697 cache_methods->get_one_authentic_pixel_from_handler;
4698}
4699
4700/*
4701%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4702% %
4703% %
4704% %
4705+ S e t P i x e l C a c h e N e x u s P i x e l s %
4706% %
4707% %
4708% %
4709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4710%
4711% SetPixelCacheNexusPixels() defines the region of the cache for the
4712% specified cache nexus.
4713%
4714% The format of the SetPixelCacheNexusPixels() method is:
4715%
cristy265a2b22012-05-11 12:48:50 +00004716% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004717% const RectangleInfo *region,NexusInfo *nexus_info,
4718% ExceptionInfo *exception)
4719%
4720% A description of each parameter follows:
4721%
4722% o image: the image.
4723%
cristy265a2b22012-05-11 12:48:50 +00004724% o mode: ReadMode, WriteMode, or IOMode.
4725%
cristy3ed852e2009-09-05 21:47:34 +00004726% o region: A pointer to the RectangleInfo structure that defines the
4727% region of this particular cache nexus.
4728%
4729% o nexus_info: the cache nexus to set.
4730%
4731% o exception: return any errors or warnings in this structure.
4732%
4733*/
cristyabd6e372010-09-15 19:11:26 +00004734
cristyf1832792012-05-08 18:38:18 +00004735static inline MagickBooleanType AcquireCacheNexusPixels(
4736 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4737 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004738{
4739 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4740 return(MagickFalse);
4741 nexus_info->mapped=MagickFalse;
cristy64c3edf2012-04-13 18:50:13 +00004742 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00004743 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004744 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004745 {
4746 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004747 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004748 nexus_info->length);
4749 }
cristy4c08aed2011-07-01 19:47:50 +00004750 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004751 {
4752 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004753 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004754 cache_info->filename);
4755 return(MagickFalse);
4756 }
4757 return(MagickTrue);
4758}
4759
cristyadf82722012-05-11 17:34:16 +00004760static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4761 const MapMode mode)
4762{
cristyfc5845e2012-05-11 18:18:13 +00004763 if (mode == ReadMode)
4764 {
4765 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4766 return;
4767 }
4768 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004769}
4770
cristy265a2b22012-05-11 12:48:50 +00004771static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004772 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4773{
4774 CacheInfo
4775 *cache_info;
4776
4777 MagickBooleanType
4778 status;
4779
cristy3ed852e2009-09-05 21:47:34 +00004780 MagickSizeType
4781 length,
4782 number_pixels;
4783
cristy3ed852e2009-09-05 21:47:34 +00004784 cache_info=(CacheInfo *) image->cache;
4785 assert(cache_info->signature == MagickSignature);
4786 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004787 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004788 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004789 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004790 {
cristybb503372010-05-27 20:51:26 +00004791 ssize_t
cristybad067a2010-02-15 17:20:55 +00004792 x,
4793 y;
cristy3ed852e2009-09-05 21:47:34 +00004794
cristyeaedf062010-05-29 22:36:02 +00004795 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4796 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004797 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4798 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004799 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004800 ((nexus_info->region.width == cache_info->columns) ||
4801 ((nexus_info->region.width % cache_info->columns) == 0)))))
4802 {
4803 MagickOffsetType
4804 offset;
4805
4806 /*
4807 Pixels are accessed directly from memory.
4808 */
4809 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4810 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004811 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004812 offset;
4813 nexus_info->metacontent=(void *) NULL;
4814 if (cache_info->metacontent_extent != 0)
4815 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4816 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004817 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004818 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004819 }
4820 }
4821 /*
4822 Pixels are stored in a cache region until they are synced to the cache.
4823 */
4824 number_pixels=(MagickSizeType) nexus_info->region.width*
4825 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004826 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004827 if (cache_info->metacontent_extent != 0)
4828 length+=number_pixels*cache_info->metacontent_extent;
4829 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004830 {
4831 nexus_info->length=length;
4832 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4833 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004834 {
4835 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004836 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004837 }
cristy3ed852e2009-09-05 21:47:34 +00004838 }
4839 else
4840 if (nexus_info->length != length)
4841 {
4842 RelinquishCacheNexusPixels(nexus_info);
4843 nexus_info->length=length;
4844 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4845 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004846 {
4847 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004848 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004849 }
cristy3ed852e2009-09-05 21:47:34 +00004850 }
4851 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004852 nexus_info->metacontent=(void *) NULL;
4853 if (cache_info->metacontent_extent != 0)
4854 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004855 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004856 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004857 return(nexus_info->pixels);
4858}
4859
4860/*
4861%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4862% %
4863% %
4864% %
4865% 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 %
4866% %
4867% %
4868% %
4869%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4870%
4871% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4872% pixel cache and returns the previous setting. A virtual pixel is any pixel
4873% access that is outside the boundaries of the image cache.
4874%
4875% The format of the SetPixelCacheVirtualMethod() method is:
4876%
cristy387430f2012-02-07 13:09:46 +00004877% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4878% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004879%
4880% A description of each parameter follows:
4881%
4882% o image: the image.
4883%
4884% o virtual_pixel_method: choose the type of virtual pixel.
4885%
cristy387430f2012-02-07 13:09:46 +00004886% o exception: return any errors or warnings in this structure.
4887%
cristy3ed852e2009-09-05 21:47:34 +00004888*/
cristy3d4cb882012-02-07 19:11:26 +00004889
4890static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4891 ExceptionInfo *exception)
4892{
4893 CacheInfo
4894 *cache_info;
4895
cristyf2719112012-05-06 18:38:46 +00004896 CacheView
4897 *image_view;
4898
cristy3d4cb882012-02-07 19:11:26 +00004899 MagickBooleanType
4900 status;
4901
4902 ssize_t
4903 y;
4904
4905 assert(image != (Image *) NULL);
4906 assert(image->signature == MagickSignature);
4907 if (image->debug != MagickFalse)
4908 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4909 assert(image->cache != (Cache) NULL);
4910 cache_info=(CacheInfo *) image->cache;
4911 assert(cache_info->signature == MagickSignature);
4912 image->matte=MagickTrue;
4913 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004914 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004915#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00004916 #pragma omp parallel for schedule(static) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00004917 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004918#endif
4919 for (y=0; y < (ssize_t) image->rows; y++)
4920 {
cristy3d4cb882012-02-07 19:11:26 +00004921 register Quantum
4922 *restrict q;
4923
4924 register ssize_t
4925 x;
4926
4927 if (status == MagickFalse)
4928 continue;
cristy23d198a2012-03-13 13:48:08 +00004929 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004930 if (q == (Quantum *) NULL)
4931 {
4932 status=MagickFalse;
4933 continue;
4934 }
4935 for (x=0; x < (ssize_t) image->columns; x++)
4936 {
4937 SetPixelAlpha(image,alpha,q);
4938 q+=GetPixelChannels(image);
4939 }
cristy23d198a2012-03-13 13:48:08 +00004940 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004941 }
cristy23d198a2012-03-13 13:48:08 +00004942 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004943 return(status);
4944}
4945
cristy387430f2012-02-07 13:09:46 +00004946MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4947 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004948{
4949 CacheInfo
4950 *cache_info;
4951
4952 VirtualPixelMethod
4953 method;
4954
4955 assert(image != (Image *) NULL);
4956 assert(image->signature == MagickSignature);
4957 if (image->debug != MagickFalse)
4958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4959 assert(image->cache != (Cache) NULL);
4960 cache_info=(CacheInfo *) image->cache;
4961 assert(cache_info->signature == MagickSignature);
4962 method=cache_info->virtual_pixel_method;
4963 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy13c10082012-05-29 11:22:12 +00004964 if ((image->columns != 0) && (image->rows != 0))
4965 switch (virtual_pixel_method)
cristy387430f2012-02-07 13:09:46 +00004966 {
cristy13c10082012-05-29 11:22:12 +00004967 case BackgroundVirtualPixelMethod:
4968 {
4969 if ((image->background_color.matte != MagickFalse) &&
4970 (image->matte == MagickFalse))
4971 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy6386b792012-06-23 17:44:57 +00004972 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4973 (IsGrayColorspace(image->colorspace) != MagickFalse))
4974 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy13c10082012-05-29 11:22:12 +00004975 break;
4976 }
4977 case TransparentVirtualPixelMethod:
4978 {
4979 if (image->matte == MagickFalse)
4980 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4981 break;
4982 }
4983 default:
4984 break;
cristy387430f2012-02-07 13:09:46 +00004985 }
cristy3ed852e2009-09-05 21:47:34 +00004986 return(method);
4987}
4988
4989/*
4990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4991% %
4992% %
4993% %
4994+ 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 %
4995% %
4996% %
4997% %
4998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4999%
5000% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5001% in-memory or disk cache. The method returns MagickTrue if the pixel region
5002% is synced, otherwise MagickFalse.
5003%
5004% The format of the SyncAuthenticPixelCacheNexus() method is:
5005%
5006% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5007% NexusInfo *nexus_info,ExceptionInfo *exception)
5008%
5009% A description of each parameter follows:
5010%
5011% o image: the image.
5012%
5013% o nexus_info: the cache nexus to sync.
5014%
5015% o exception: return any errors or warnings in this structure.
5016%
5017*/
cristya6577ff2011-09-02 19:54:26 +00005018MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005019 NexusInfo *nexus_info,ExceptionInfo *exception)
5020{
5021 CacheInfo
5022 *cache_info;
5023
5024 MagickBooleanType
5025 status;
5026
5027 /*
5028 Transfer pixels to the cache.
5029 */
5030 assert(image != (Image *) NULL);
5031 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005032 if (image->cache == (Cache) NULL)
5033 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5034 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005035 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005036 if (cache_info->type == UndefinedCache)
5037 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005038 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005039 return(MagickTrue);
5040 assert(cache_info->signature == MagickSignature);
5041 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005042 if ((cache_info->metacontent_extent != 0) &&
5043 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005044 return(MagickFalse);
5045 return(status);
5046}
5047
5048/*
5049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5050% %
5051% %
5052% %
5053+ S y n c A u t h e n t i c P i x e l C a c h e %
5054% %
5055% %
5056% %
5057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5058%
5059% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5060% or disk cache. The method returns MagickTrue if the pixel region is synced,
5061% otherwise MagickFalse.
5062%
5063% The format of the SyncAuthenticPixelsCache() method is:
5064%
5065% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5066% ExceptionInfo *exception)
5067%
5068% A description of each parameter follows:
5069%
5070% o image: the image.
5071%
5072% o exception: return any errors or warnings in this structure.
5073%
5074*/
5075static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5076 ExceptionInfo *exception)
5077{
5078 CacheInfo
5079 *cache_info;
5080
cristy5c9e6f22010-09-17 17:31:01 +00005081 const int
5082 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005083
cristy4c08aed2011-07-01 19:47:50 +00005084 MagickBooleanType
5085 status;
5086
cristye7cc7cf2010-09-21 13:26:47 +00005087 assert(image != (Image *) NULL);
5088 assert(image->signature == MagickSignature);
5089 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005090 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005091 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005092 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005093 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5094 exception);
5095 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005096}
5097
5098/*
5099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5100% %
5101% %
5102% %
5103% S y n c A u t h e n t i c P i x e l s %
5104% %
5105% %
5106% %
5107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5108%
5109% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5110% The method returns MagickTrue if the pixel region is flushed, otherwise
5111% MagickFalse.
5112%
5113% The format of the SyncAuthenticPixels() method is:
5114%
5115% MagickBooleanType SyncAuthenticPixels(Image *image,
5116% ExceptionInfo *exception)
5117%
5118% A description of each parameter follows:
5119%
5120% o image: the image.
5121%
5122% o exception: return any errors or warnings in this structure.
5123%
5124*/
5125MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5126 ExceptionInfo *exception)
5127{
5128 CacheInfo
5129 *cache_info;
5130
cristy2036f5c2010-09-19 21:18:17 +00005131 const int
5132 id = GetOpenMPThreadId();
5133
cristy4c08aed2011-07-01 19:47:50 +00005134 MagickBooleanType
5135 status;
5136
cristy3ed852e2009-09-05 21:47:34 +00005137 assert(image != (Image *) NULL);
5138 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005139 assert(image->cache != (Cache) NULL);
5140 cache_info=(CacheInfo *) image->cache;
5141 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005142 if (cache_info->methods.sync_authentic_pixels_handler !=
5143 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005144 {
5145 status=cache_info->methods.sync_authentic_pixels_handler(image,
5146 exception);
5147 return(status);
5148 }
cristy2036f5c2010-09-19 21:18:17 +00005149 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005150 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5151 exception);
5152 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005153}
5154
5155/*
5156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5157% %
5158% %
5159% %
cristyd1dd6e42011-09-04 01:46:08 +00005160+ 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 +00005161% %
5162% %
5163% %
5164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5165%
5166% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5167% The method returns MagickTrue if the pixel region is flushed, otherwise
5168% MagickFalse.
5169%
5170% The format of the SyncImagePixelCache() method is:
5171%
5172% MagickBooleanType SyncImagePixelCache(Image *image,
5173% ExceptionInfo *exception)
5174%
5175% A description of each parameter follows:
5176%
5177% o image: the image.
5178%
5179% o exception: return any errors or warnings in this structure.
5180%
5181*/
cristyd1dd6e42011-09-04 01:46:08 +00005182MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005183 ExceptionInfo *exception)
5184{
5185 CacheInfo
5186 *cache_info;
5187
5188 assert(image != (Image *) NULL);
5189 assert(exception != (ExceptionInfo *) NULL);
5190 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5191 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5192}
5193
5194/*
5195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5196% %
5197% %
5198% %
cristy4c08aed2011-07-01 19:47:50 +00005199+ 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 +00005200% %
5201% %
5202% %
5203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5204%
cristy4c08aed2011-07-01 19:47:50 +00005205% WritePixelCacheMetacontent() writes the meta-content to the specified region
5206% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005207%
cristy4c08aed2011-07-01 19:47:50 +00005208% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005209%
cristy4c08aed2011-07-01 19:47:50 +00005210% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005211% NexusInfo *nexus_info,ExceptionInfo *exception)
5212%
5213% A description of each parameter follows:
5214%
5215% o cache_info: the pixel cache.
5216%
cristy4c08aed2011-07-01 19:47:50 +00005217% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005218%
5219% o exception: return any errors or warnings in this structure.
5220%
5221*/
cristy4c08aed2011-07-01 19:47:50 +00005222static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005223 NexusInfo *nexus_info,ExceptionInfo *exception)
5224{
5225 MagickOffsetType
5226 count,
5227 offset;
5228
5229 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005230 extent,
5231 length;
cristy3ed852e2009-09-05 21:47:34 +00005232
cristy4c08aed2011-07-01 19:47:50 +00005233 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005234 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005235
cristybb503372010-05-27 20:51:26 +00005236 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005237 y;
5238
cristybb503372010-05-27 20:51:26 +00005239 size_t
cristy3ed852e2009-09-05 21:47:34 +00005240 rows;
5241
cristy4c08aed2011-07-01 19:47:50 +00005242 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005243 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005244 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005245 return(MagickTrue);
5246 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5247 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005248 length=(MagickSizeType) nexus_info->region.width*
5249 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005250 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005251 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005252 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005253 switch (cache_info->type)
5254 {
5255 case MemoryCache:
5256 case MapCache:
5257 {
cristy4c08aed2011-07-01 19:47:50 +00005258 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005259 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005260
5261 /*
cristy4c08aed2011-07-01 19:47:50 +00005262 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005263 */
cristydd341db2010-03-04 19:06:38 +00005264 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005265 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005266 {
cristy48078b12010-09-23 17:11:01 +00005267 length=extent;
cristydd341db2010-03-04 19:06:38 +00005268 rows=1UL;
5269 }
cristy4c08aed2011-07-01 19:47:50 +00005270 q=(unsigned char *) cache_info->metacontent+offset*
5271 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005272 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005273 {
cristy8f036fe2010-09-18 02:02:00 +00005274 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005275 p+=nexus_info->region.width*cache_info->metacontent_extent;
5276 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005277 }
5278 break;
5279 }
5280 case DiskCache:
5281 {
5282 /*
cristy4c08aed2011-07-01 19:47:50 +00005283 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005284 */
5285 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5286 {
5287 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5288 cache_info->cache_filename);
5289 return(MagickFalse);
5290 }
cristydd341db2010-03-04 19:06:38 +00005291 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005292 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005293 {
cristy48078b12010-09-23 17:11:01 +00005294 length=extent;
cristydd341db2010-03-04 19:06:38 +00005295 rows=1UL;
5296 }
cristy48078b12010-09-23 17:11:01 +00005297 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005298 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005299 {
cristy48078b12010-09-23 17:11:01 +00005300 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005301 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005302 cache_info->metacontent_extent,length,(const unsigned char *) p);
5303 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005304 break;
cristy4c08aed2011-07-01 19:47:50 +00005305 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005306 offset+=cache_info->columns;
5307 }
cristyc11dace2012-01-24 16:39:46 +00005308 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5309 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005310 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005311 {
5312 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5313 cache_info->cache_filename);
5314 return(MagickFalse);
5315 }
5316 break;
5317 }
5318 default:
5319 break;
5320 }
5321 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005322 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005323 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005324 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005325 nexus_info->region.width,(double) nexus_info->region.height,(double)
5326 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005327 return(MagickTrue);
5328}
5329
5330/*
5331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5332% %
5333% %
5334% %
5335+ W r i t e C a c h e P i x e l s %
5336% %
5337% %
5338% %
5339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5340%
5341% WritePixelCachePixels() writes image pixels to the specified region of the
5342% pixel cache.
5343%
5344% The format of the WritePixelCachePixels() method is:
5345%
5346% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5347% NexusInfo *nexus_info,ExceptionInfo *exception)
5348%
5349% A description of each parameter follows:
5350%
5351% o cache_info: the pixel cache.
5352%
5353% o nexus_info: the cache nexus to write the pixels.
5354%
5355% o exception: return any errors or warnings in this structure.
5356%
5357*/
5358static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5359 NexusInfo *nexus_info,ExceptionInfo *exception)
5360{
5361 MagickOffsetType
5362 count,
5363 offset;
5364
5365 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005366 extent,
5367 length;
cristy3ed852e2009-09-05 21:47:34 +00005368
cristy4c08aed2011-07-01 19:47:50 +00005369 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005370 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005371
cristybb503372010-05-27 20:51:26 +00005372 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005373 y;
5374
cristybb503372010-05-27 20:51:26 +00005375 size_t
cristy3ed852e2009-09-05 21:47:34 +00005376 rows;
5377
cristy4c08aed2011-07-01 19:47:50 +00005378 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005379 return(MagickTrue);
5380 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5381 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005382 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005383 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005384 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005385 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005386 p=nexus_info->pixels;
5387 switch (cache_info->type)
5388 {
5389 case MemoryCache:
5390 case MapCache:
5391 {
cristy4c08aed2011-07-01 19:47:50 +00005392 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005393 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005394
5395 /*
5396 Write pixels to memory.
5397 */
cristydd341db2010-03-04 19:06:38 +00005398 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005399 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005400 {
cristy48078b12010-09-23 17:11:01 +00005401 length=extent;
cristydd341db2010-03-04 19:06:38 +00005402 rows=1UL;
5403 }
cristyed231572011-07-14 02:18:59 +00005404 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005405 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005406 {
cristy8f036fe2010-09-18 02:02:00 +00005407 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005408 p+=nexus_info->region.width*cache_info->number_channels;
5409 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005410 }
5411 break;
5412 }
5413 case DiskCache:
5414 {
5415 /*
5416 Write pixels to disk.
5417 */
5418 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5419 {
5420 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5421 cache_info->cache_filename);
5422 return(MagickFalse);
5423 }
cristydd341db2010-03-04 19:06:38 +00005424 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005425 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005426 {
cristy48078b12010-09-23 17:11:01 +00005427 length=extent;
cristydd341db2010-03-04 19:06:38 +00005428 rows=1UL;
5429 }
cristybb503372010-05-27 20:51:26 +00005430 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005431 {
5432 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005433 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005434 p);
5435 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005436 break;
cristyed231572011-07-14 02:18:59 +00005437 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005438 offset+=cache_info->columns;
5439 }
cristyc11dace2012-01-24 16:39:46 +00005440 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5441 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005442 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005443 {
5444 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5445 cache_info->cache_filename);
5446 return(MagickFalse);
5447 }
5448 break;
5449 }
5450 default:
5451 break;
5452 }
5453 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005454 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005455 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005456 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005457 nexus_info->region.width,(double) nexus_info->region.height,(double)
5458 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005459 return(MagickTrue);
5460}