blob: fb0929ea960ab6b07d63a5c24ca7113a5f407285 [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"
cristy3d9f5ba2012-06-26 13:37:31 +000049#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000050#include "MagickCore/composite-private.h"
51#include "MagickCore/exception.h"
52#include "MagickCore/exception-private.h"
53#include "MagickCore/geometry.h"
54#include "MagickCore/list.h"
55#include "MagickCore/log.h"
56#include "MagickCore/magick.h"
57#include "MagickCore/memory_.h"
cristyadf82722012-05-11 17:34:16 +000058#include "MagickCore/memory-private.h"
cristyd2d11ec2012-03-28 13:53:49 +000059#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000060#include "MagickCore/pixel.h"
61#include "MagickCore/pixel-accessor.h"
62#include "MagickCore/policy.h"
63#include "MagickCore/quantum.h"
64#include "MagickCore/random_.h"
65#include "MagickCore/resource_.h"
66#include "MagickCore/semaphore.h"
67#include "MagickCore/splay-tree.h"
68#include "MagickCore/string_.h"
69#include "MagickCore/string-private.h"
70#include "MagickCore/thread-private.h"
71#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000072#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000073#if defined(MAGICKCORE_ZLIB_DELEGATE)
74#include "zlib.h"
75#endif
76
77/*
cristy30097232010-07-01 02:16:30 +000078 Define declarations.
79*/
80#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
cristyc11dace2012-01-24 16:39:46 +000081#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
82 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
cristy30097232010-07-01 02:16:30 +000083
84/*
cristy3ed852e2009-09-05 21:47:34 +000085 Typedef declarations.
86*/
87typedef struct _MagickModulo
88{
cristybb503372010-05-27 20:51:26 +000089 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000090 quotient,
91 remainder;
92} MagickModulo;
93
94struct _NexusInfo
95{
96 MagickBooleanType
97 mapped;
98
99 RectangleInfo
100 region;
101
102 MagickSizeType
103 length;
104
cristy4c08aed2011-07-01 19:47:50 +0000105 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000106 *cache,
107 *pixels;
108
cristy4c08aed2011-07-01 19:47:50 +0000109 void
110 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000111
cristybb503372010-05-27 20:51:26 +0000112 size_t
cristy3ed852e2009-09-05 21:47:34 +0000113 signature;
114};
115
116/*
117 Forward declarations.
118*/
119#if defined(__cplusplus) || defined(c_plusplus)
120extern "C" {
121#endif
122
cristy19596d62012-02-19 00:24:59 +0000123static Cache
124 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
125 magick_hot_spot;
126
cristy4c08aed2011-07-01 19:47:50 +0000127static const Quantum
cristybb503372010-05-27 20:51:26 +0000128 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000129 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 *GetVirtualPixelsCache(const Image *);
131
cristy4c08aed2011-07-01 19:47:50 +0000132static const void
133 *GetVirtualMetacontentFromCache(const Image *);
134
cristy3ed852e2009-09-05 21:47:34 +0000135static MagickBooleanType
cristy74ce05d2012-05-06 18:41:18 +0000136 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
137 ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000138 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000139 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000140 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000141 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
143 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000144 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000145 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
146
cristy4c08aed2011-07-01 19:47:50 +0000147static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000148 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
149 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000150 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
151 const size_t,ExceptionInfo *),
cristy265a2b22012-05-11 12:48:50 +0000152 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
153 NexusInfo *,ExceptionInfo *) magick_hot_spot;
cristy3ed852e2009-09-05 21:47:34 +0000154
155#if defined(__cplusplus) || defined(c_plusplus)
156}
157#endif
158
159/*
160 Global declarations.
161*/
162static volatile MagickBooleanType
163 instantiate_cache = MagickFalse;
164
165static SemaphoreInfo
166 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000167
168/*
169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170% %
171% %
172% %
173+ A c q u i r e P i x e l C a c h e %
174% %
175% %
176% %
177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178%
179% AcquirePixelCache() acquires a pixel cache.
180%
181% The format of the AcquirePixelCache() method is:
182%
cristybb503372010-05-27 20:51:26 +0000183% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184%
185% A description of each parameter follows:
186%
187% o number_threads: the number of nexus threads.
188%
189*/
cristya6577ff2011-09-02 19:54:26 +0000190MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000191{
192 CacheInfo
193 *cache_info;
194
cristya64b85d2011-09-14 01:02:31 +0000195 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000196 if (cache_info == (CacheInfo *) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
199 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000200 cache_info->mode=IOMode;
cristyc511e882012-04-16 21:11:14 +0000201 cache_info->colorspace=sRGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +0000202 cache_info->file=(-1);
203 cache_info->id=GetMagickThreadId();
204 cache_info->number_threads=number_threads;
cristy134c76e2012-08-05 01:21:44 +0000205 if (cache_info->number_threads == 0)
cristy9357bdd2012-07-30 12:28:34 +0000206 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
cristy134c76e2012-08-05 01:21:44 +0000207 if (cache_info->number_threads == 0)
208 cache_info->number_threads=1;
cristy3ed852e2009-09-05 21:47:34 +0000209 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
210 if (cache_info->nexus_info == (NexusInfo **) NULL)
211 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000212 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000213 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000214 cache_info->disk_semaphore=AllocateSemaphoreInfo();
215 cache_info->debug=IsEventLogging();
216 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000217 return((Cache ) cache_info);
218}
219
220/*
221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222% %
223% %
224% %
225% A c q u i r e P i x e l C a c h e N e x u s %
226% %
227% %
228% %
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230%
231% AcquirePixelCacheNexus() allocates the NexusInfo structure.
232%
233% The format of the AcquirePixelCacheNexus method is:
234%
cristybb503372010-05-27 20:51:26 +0000235% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000236%
237% A description of each parameter follows:
238%
239% o number_threads: the number of nexus threads.
240%
241*/
cristya6577ff2011-09-02 19:54:26 +0000242MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000243{
cristy3ed852e2009-09-05 21:47:34 +0000244 NexusInfo
245 **nexus_info;
246
cristye076a6e2010-08-15 19:59:43 +0000247 register ssize_t
248 i;
249
cristy64c3edf2012-04-13 18:50:13 +0000250 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000251 sizeof(*nexus_info));
252 if (nexus_info == (NexusInfo **) NULL)
253 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000254 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
255 sizeof(**nexus_info));
256 if (nexus_info[0] == (NexusInfo *) NULL)
257 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
258 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000259 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000260 {
cristye5f87c82012-02-14 12:44:17 +0000261 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000262 nexus_info[i]->signature=MagickSignature;
263 }
264 return(nexus_info);
265}
266
267/*
268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269% %
270% %
271% %
cristyd43a46b2010-01-21 02:13:41 +0000272+ A c q u i r e P i x e l C a c h e P i x e l s %
273% %
274% %
275% %
276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277%
278% AcquirePixelCachePixels() returns the pixels associated with the specified
279% image.
280%
281% The format of the AcquirePixelCachePixels() method is:
282%
283% const void *AcquirePixelCachePixels(const Image *image,
284% MagickSizeType *length,ExceptionInfo *exception)
285%
286% A description of each parameter follows:
287%
288% o image: the image.
289%
290% o length: the pixel cache length.
291%
292% o exception: return any errors or warnings in this structure.
293%
294*/
cristyd1dd6e42011-09-04 01:46:08 +0000295MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000296 MagickSizeType *length,ExceptionInfo *exception)
297{
298 CacheInfo
299 *cache_info;
300
301 assert(image != (const Image *) NULL);
302 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000303 assert(exception != (ExceptionInfo *) NULL);
304 assert(exception->signature == MagickSignature);
305 assert(image->cache != (Cache) NULL);
306 cache_info=(CacheInfo *) image->cache;
307 assert(cache_info->signature == MagickSignature);
308 *length=0;
309 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
310 return((const void *) NULL);
311 *length=cache_info->length;
312 return((const void *) cache_info->pixels);
313}
314
315/*
316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317% %
318% %
319% %
cristyf34a1452009-10-24 22:29:27 +0000320+ C a c h e C o m p o n e n t G e n e s i s %
321% %
322% %
323% %
324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325%
326% CacheComponentGenesis() instantiates the cache component.
327%
328% The format of the CacheComponentGenesis method is:
329%
330% MagickBooleanType CacheComponentGenesis(void)
331%
332*/
cristy5ff4eaf2011-09-03 01:38:02 +0000333MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000334{
cristy165b6092009-10-26 13:52:10 +0000335 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000336 return(MagickTrue);
337}
338
339/*
340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341% %
342% %
343% %
344+ C a c h e C o m p o n e n t T e r m i n u s %
345% %
346% %
347% %
348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349%
350% CacheComponentTerminus() destroys the cache component.
351%
352% The format of the CacheComponentTerminus() method is:
353%
354% CacheComponentTerminus(void)
355%
356*/
cristy5ff4eaf2011-09-03 01:38:02 +0000357MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000358{
cristy18b17442009-10-25 18:36:48 +0000359 if (cache_semaphore == (SemaphoreInfo *) NULL)
360 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000361 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000362 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000363 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000364 DestroySemaphoreInfo(&cache_semaphore);
365}
366
367/*
368%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
369% %
370% %
371% %
cristy3ed852e2009-09-05 21:47:34 +0000372+ C l o n e P i x e l C a c h e %
373% %
374% %
375% %
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377%
378% ClonePixelCache() clones a pixel cache.
379%
380% The format of the ClonePixelCache() method is:
381%
382% Cache ClonePixelCache(const Cache cache)
383%
384% A description of each parameter follows:
385%
386% o cache: the pixel cache.
387%
388*/
cristya6577ff2011-09-02 19:54:26 +0000389MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000390{
391 CacheInfo
392 *clone_info;
393
394 const CacheInfo
395 *cache_info;
396
cristy9f027d12011-09-21 01:17:17 +0000397 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000398 cache_info=(const CacheInfo *) cache;
399 assert(cache_info->signature == MagickSignature);
400 if (cache_info->debug != MagickFalse)
401 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
402 cache_info->filename);
403 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
404 if (clone_info == (Cache) NULL)
405 return((Cache) NULL);
406 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
407 return((Cache ) clone_info);
408}
409
410/*
411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412% %
413% %
414% %
cristy60c44a82009-10-07 00:58:49 +0000415+ 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 +0000416% %
417% %
418% %
419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
420% ClonePixelCachePixels() clones the source pixel cache to the destination
421% cache.
422%
423% The format of the ClonePixelCachePixels() method is:
424%
425% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
426% CacheInfo *source_info,ExceptionInfo *exception)
427%
428% A description of each parameter follows:
429%
430% o cache_info: the pixel cache.
431%
432% o source_info: the source pixel cache.
433%
434% o exception: return any errors or warnings in this structure.
435%
436*/
437
438static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
439{
440 int
441 status;
442
cristy5ee247a2010-02-12 15:42:34 +0000443 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000444 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000445 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000446 {
447 status=close(cache_info->file);
448 cache_info->file=(-1);
449 RelinquishMagickResource(FileResource,1);
450 }
cristyf84a1932010-01-03 18:00:18 +0000451 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000452 return(status == -1 ? MagickFalse : MagickTrue);
453}
454
cristy3ed852e2009-09-05 21:47:34 +0000455static inline MagickSizeType MagickMax(const MagickSizeType x,
456 const MagickSizeType y)
457{
458 if (x > y)
459 return(x);
460 return(y);
461}
462
463static inline MagickSizeType MagickMin(const MagickSizeType x,
464 const MagickSizeType y)
465{
466 if (x < y)
467 return(x);
468 return(y);
469}
470
471static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
472 const MapMode mode)
473{
474 int
475 file;
476
477 /*
478 Open pixel cache on disk.
479 */
cristyf84a1932010-01-03 18:00:18 +0000480 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000481 if (cache_info->file != -1)
482 {
cristyf84a1932010-01-03 18:00:18 +0000483 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000484 return(MagickTrue); /* cache already open */
485 }
cristy3ed852e2009-09-05 21:47:34 +0000486 if (*cache_info->cache_filename == '\0')
487 file=AcquireUniqueFileResource(cache_info->cache_filename);
488 else
489 switch (mode)
490 {
491 case ReadMode:
492 {
cristy18c6c272011-09-23 14:40:37 +0000493 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000494 break;
495 }
496 case WriteMode:
497 {
cristy18c6c272011-09-23 14:40:37 +0000498 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
499 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000500 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000501 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000502 break;
503 }
504 case IOMode:
505 default:
506 {
cristy18c6c272011-09-23 14:40:37 +0000507 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000508 O_EXCL,S_MODE);
509 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000510 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000511 break;
512 }
513 }
514 if (file == -1)
515 {
cristyf84a1932010-01-03 18:00:18 +0000516 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000517 return(MagickFalse);
518 }
519 (void) AcquireMagickResource(FileResource,1);
520 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000521 cache_info->mode=mode;
cristyf84a1932010-01-03 18:00:18 +0000522 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000523 return(MagickTrue);
524}
525
cristyf1832792012-05-08 18:38:18 +0000526static inline MagickOffsetType ReadPixelCacheRegion(
527 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
528 const MagickSizeType length,unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000529{
530 register MagickOffsetType
531 i;
532
533 ssize_t
534 count;
535
536#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000537 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000538 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000539 {
cristyf84a1932010-01-03 18:00:18 +0000540 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000541 return((MagickOffsetType) -1);
542 }
543#endif
544 count=0;
545 for (i=0; i < (MagickOffsetType) length; i+=count)
546 {
547#if !defined(MAGICKCORE_HAVE_PREAD)
548 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
549 (MagickSizeType) SSIZE_MAX));
550#else
551 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000552 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000553#endif
554 if (count > 0)
555 continue;
556 count=0;
557 if (errno != EINTR)
558 {
559 i=(-1);
560 break;
561 }
562 }
563#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000564 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000565#endif
566 return(i);
567}
568
cristyf1832792012-05-08 18:38:18 +0000569static inline MagickOffsetType WritePixelCacheRegion(
570 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
571 const MagickSizeType length,const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000572{
573 register MagickOffsetType
574 i;
575
576 ssize_t
577 count;
578
579#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000580 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000581 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000582 {
cristyf84a1932010-01-03 18:00:18 +0000583 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000584 return((MagickOffsetType) -1);
585 }
586#endif
587 count=0;
588 for (i=0; i < (MagickOffsetType) length; i+=count)
589 {
590#if !defined(MAGICKCORE_HAVE_PWRITE)
591 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
592 (MagickSizeType) SSIZE_MAX));
593#else
594 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000595 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000596#endif
597 if (count > 0)
598 continue;
599 count=0;
600 if (errno != EINTR)
601 {
602 i=(-1);
603 break;
604 }
605 }
606#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000607 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000608#endif
609 return(i);
610}
611
cristy4c08aed2011-07-01 19:47:50 +0000612static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000613 CacheInfo *cache_info,ExceptionInfo *exception)
614{
615 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000616 count;
cristy3ed852e2009-09-05 21:47:34 +0000617
cristy4c08aed2011-07-01 19:47:50 +0000618 register MagickOffsetType
619 i;
cristye076a6e2010-08-15 19:59:43 +0000620
cristybb503372010-05-27 20:51:26 +0000621 size_t
cristy4c08aed2011-07-01 19:47:50 +0000622 length;
cristy3ed852e2009-09-05 21:47:34 +0000623
cristy4c08aed2011-07-01 19:47:50 +0000624 unsigned char
625 *blob;
626
627 /*
628 Clone pixel cache (both caches on disk).
629 */
cristy3ed852e2009-09-05 21:47:34 +0000630 if (cache_info->debug != MagickFalse)
631 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000632 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000633 sizeof(*blob));
634 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000635 {
cristy4c08aed2011-07-01 19:47:50 +0000636 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000637 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000638 cache_info->filename);
639 return(MagickFalse);
640 }
cristy3dedf062011-07-02 14:07:40 +0000641 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000642 {
643 blob=(unsigned char *) RelinquishMagickMemory(blob);
644 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
645 cache_info->cache_filename);
646 return(MagickFalse);
647 }
cristy3dedf062011-07-02 14:07:40 +0000648 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000649 {
650 (void) ClosePixelCacheOnDisk(cache_info);
651 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000652 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
653 clone_info->cache_filename);
654 return(MagickFalse);
655 }
cristy4c08aed2011-07-01 19:47:50 +0000656 count=0;
657 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000658 {
cristy4c08aed2011-07-01 19:47:50 +0000659 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
660 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
661 blob);
662 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000663 {
cristy4c08aed2011-07-01 19:47:50 +0000664 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
665 cache_info->cache_filename);
666 break;
cristy3ed852e2009-09-05 21:47:34 +0000667 }
cristy4c08aed2011-07-01 19:47:50 +0000668 length=(size_t) count;
669 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
670 if ((MagickSizeType) count != length)
671 {
672 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
673 clone_info->cache_filename);
674 break;
675 }
676 }
677 (void) ClosePixelCacheOnDisk(clone_info);
678 (void) ClosePixelCacheOnDisk(cache_info);
679 blob=(unsigned char *) RelinquishMagickMemory(blob);
680 if (i < (MagickOffsetType) cache_info->length)
681 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000682 return(MagickTrue);
683}
684
cristyfd24a062012-01-02 14:46:34 +0000685static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000686 CacheInfo *cache_info,ExceptionInfo *exception)
687{
688 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000689 count;
cristy3ed852e2009-09-05 21:47:34 +0000690
cristy4c08aed2011-07-01 19:47:50 +0000691 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000692 {
cristy3ed852e2009-09-05 21:47:34 +0000693 /*
cristy4c08aed2011-07-01 19:47:50 +0000694 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000695 */
cristy4c08aed2011-07-01 19:47:50 +0000696 if (cache_info->debug != MagickFalse)
697 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
698 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
699 cache_info->length);
700 return(MagickTrue);
701 }
702 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
703 {
704 /*
705 Clone pixel cache (one cache on disk, one in memory).
706 */
707 if (cache_info->debug != MagickFalse)
708 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
709 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000710 {
cristy4c08aed2011-07-01 19:47:50 +0000711 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000712 cache_info->cache_filename);
713 return(MagickFalse);
714 }
cristy4c08aed2011-07-01 19:47:50 +0000715 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
716 cache_info->length,(unsigned char *) clone_info->pixels);
717 (void) ClosePixelCacheOnDisk(cache_info);
718 if ((MagickSizeType) count != cache_info->length)
719 {
720 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
721 cache_info->cache_filename);
722 return(MagickFalse);
723 }
724 return(MagickTrue);
725 }
726 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
727 {
728 /*
729 Clone pixel cache (one cache on disk, one in memory).
730 */
731 if (clone_info->debug != MagickFalse)
732 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
733 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
734 {
735 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
736 clone_info->cache_filename);
737 return(MagickFalse);
738 }
739 count=WritePixelCacheRegion(clone_info,clone_info->offset,
740 clone_info->length,(unsigned char *) cache_info->pixels);
741 (void) ClosePixelCacheOnDisk(clone_info);
742 if ((MagickSizeType) count != clone_info->length)
743 {
744 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
745 clone_info->cache_filename);
746 return(MagickFalse);
747 }
748 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000749 }
750 /*
cristy4c08aed2011-07-01 19:47:50 +0000751 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000752 */
cristy4c08aed2011-07-01 19:47:50 +0000753 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000754}
755
cristyfd24a062012-01-02 14:46:34 +0000756static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000757 CacheInfo *cache_info,ExceptionInfo *exception)
758{
cristy4c08aed2011-07-01 19:47:50 +0000759 MagickBooleanType
760 status;
cristy3ed852e2009-09-05 21:47:34 +0000761
cristy4c08aed2011-07-01 19:47:50 +0000762 MagickOffsetType
763 cache_offset,
764 clone_offset,
765 count;
766
767 register ssize_t
768 x;
769
cristyfd24a062012-01-02 14:46:34 +0000770 register unsigned char
771 *p;
772
cristy4c08aed2011-07-01 19:47:50 +0000773 size_t
cristy3ed852e2009-09-05 21:47:34 +0000774 length;
775
cristy4c08aed2011-07-01 19:47:50 +0000776 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000777 y;
778
cristy4c08aed2011-07-01 19:47:50 +0000779 unsigned char
780 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000781
cristy4c08aed2011-07-01 19:47:50 +0000782 /*
783 Clone pixel cache (unoptimized).
784 */
cristy3ed852e2009-09-05 21:47:34 +0000785 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000786 {
cristy4c08aed2011-07-01 19:47:50 +0000787 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
789 else
790 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
792 else
793 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
794 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
795 else
796 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
797 }
cristyed231572011-07-14 02:18:59 +0000798 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
799 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000800 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000801 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000802 if (blob == (unsigned char *) NULL)
803 {
804 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000805 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000806 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000807 return(MagickFalse);
808 }
cristy4c08aed2011-07-01 19:47:50 +0000809 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
810 cache_offset=0;
811 clone_offset=0;
812 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000813 {
cristy4c08aed2011-07-01 19:47:50 +0000814 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000815 {
cristy4c08aed2011-07-01 19:47:50 +0000816 blob=(unsigned char *) RelinquishMagickMemory(blob);
817 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000818 cache_info->cache_filename);
819 return(MagickFalse);
820 }
cristy4c08aed2011-07-01 19:47:50 +0000821 cache_offset=cache_info->offset;
822 }
823 if (clone_info->type == DiskCache)
824 {
cristy3dedf062011-07-02 14:07:40 +0000825 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000826 {
cristy4c08aed2011-07-01 19:47:50 +0000827 blob=(unsigned char *) RelinquishMagickMemory(blob);
828 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
829 clone_info->cache_filename);
830 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000831 }
cristy4c08aed2011-07-01 19:47:50 +0000832 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000833 }
834 /*
cristy4c08aed2011-07-01 19:47:50 +0000835 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000836 */
cristy4c08aed2011-07-01 19:47:50 +0000837 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000838 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000839 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000840 {
cristy4c08aed2011-07-01 19:47:50 +0000841 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000842 {
cristy9e0719b2011-12-29 03:45:45 +0000843 register ssize_t
844 i;
845
cristy3ed852e2009-09-05 21:47:34 +0000846 /*
cristy4c08aed2011-07-01 19:47:50 +0000847 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000848 */
cristyed231572011-07-14 02:18:59 +0000849 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000850 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000851 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000852 else
853 {
cristyfd24a062012-01-02 14:46:34 +0000854 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000855 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000856 {
cristy4c08aed2011-07-01 19:47:50 +0000857 status=MagickFalse;
858 break;
cristy3ed852e2009-09-05 21:47:34 +0000859 }
860 }
cristy4c08aed2011-07-01 19:47:50 +0000861 cache_offset+=length;
862 if ((y < (ssize_t) clone_info->rows) &&
863 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000864 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
cristy9e0719b2011-12-29 03:45:45 +0000866 PixelChannel
867 channel;
868
869 PixelTrait
870 traits;
871
872 ssize_t
873 offset;
874
cristy4c08aed2011-07-01 19:47:50 +0000875 /*
cristy3b8fe922011-12-29 18:56:23 +0000876 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000877 */
cristy9e0719b2011-12-29 03:45:45 +0000878 channel=clone_info->channel_map[i].channel;
879 traits=cache_info->channel_map[channel].traits;
880 if (traits == UndefinedPixelTrait)
881 {
cristy0f4425e2011-12-31 20:33:02 +0000882 clone_offset+=sizeof(Quantum);
883 continue;
cristy9e0719b2011-12-29 03:45:45 +0000884 }
cristy0f4425e2011-12-31 20:33:02 +0000885 offset=cache_info->channel_map[channel].offset;
886 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000887 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
888 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000889 else
890 {
cristy0f4425e2011-12-31 20:33:02 +0000891 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000892 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000893 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000894 {
cristy0f4425e2011-12-31 20:33:02 +0000895 status=MagickFalse;
896 break;
cristy4c08aed2011-07-01 19:47:50 +0000897 }
898 }
cristy9e0719b2011-12-29 03:45:45 +0000899 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000900 }
901 }
cristyac245f82012-05-05 17:13:57 +0000902 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000903 {
904 /*
905 Set remaining columns as undefined.
906 */
cristy888e6132012-04-23 19:54:54 +0000907 length=clone_info->number_channels*sizeof(Quantum);
908 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
909 for ( ; x < (ssize_t) clone_info->columns; x++)
910 {
911 if (clone_info->type != DiskCache)
912 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
913 blob,length);
914 else
915 {
916 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
917 if ((MagickSizeType) count != length)
918 {
919 status=MagickFalse;
920 break;
cristye04362f2012-04-23 15:33:05 +0000921 }
cristy888e6132012-04-23 19:54:54 +0000922 }
923 clone_offset+=length;
924 }
cristye04362f2012-04-23 15:33:05 +0000925 }
cristy4c08aed2011-07-01 19:47:50 +0000926 }
cristyed231572011-07-14 02:18:59 +0000927 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000928 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
929 for ( ; y < (ssize_t) clone_info->rows; y++)
930 {
931 /*
cristy9e0719b2011-12-29 03:45:45 +0000932 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000933 */
934 for (x=0; x < (ssize_t) clone_info->columns; x++)
935 {
936 if (clone_info->type != DiskCache)
937 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
938 length);
939 else
940 {
941 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
942 if ((MagickSizeType) count != length)
943 {
944 status=MagickFalse;
945 break;
946 }
947 }
948 clone_offset+=length;
949 }
950 }
cristy9e0719b2011-12-29 03:45:45 +0000951 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000952 (clone_info->metacontent_extent != 0))
953 {
954 /*
955 Clone metacontent.
956 */
957 for (y=0; y < (ssize_t) cache_info->rows; y++)
958 {
959 for (x=0; x < (ssize_t) cache_info->columns; x++)
960 {
961 /*
962 Read a set of metacontent.
963 */
964 length=cache_info->metacontent_extent;
965 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000966 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000967 else
968 {
cristyfd24a062012-01-02 14:46:34 +0000969 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000970 if ((MagickSizeType) count != length)
971 {
972 status=MagickFalse;
973 break;
974 }
975 }
976 cache_offset+=length;
977 if ((y < (ssize_t) clone_info->rows) &&
978 (x < (ssize_t) clone_info->columns))
979 {
980 /*
981 Write a set of metacontent.
982 */
983 length=clone_info->metacontent_extent;
984 if (clone_info->type != DiskCache)
985 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000986 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000987 else
988 {
cristyfd24a062012-01-02 14:46:34 +0000989 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000990 if ((MagickSizeType) count != length)
991 {
992 status=MagickFalse;
993 break;
994 }
995 }
996 clone_offset+=length;
997 }
998 }
999 length=clone_info->metacontent_extent;
1000 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1001 for ( ; x < (ssize_t) clone_info->columns; x++)
1002 {
1003 /*
cristy9e0719b2011-12-29 03:45:45 +00001004 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001005 */
1006 if (clone_info->type != DiskCache)
1007 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1008 blob,length);
1009 else
1010 {
cristy208b1002011-08-07 18:51:50 +00001011 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001012 if ((MagickSizeType) count != length)
1013 {
1014 status=MagickFalse;
1015 break;
1016 }
1017 }
1018 clone_offset+=length;
1019 }
1020 }
cristyac245f82012-05-05 17:13:57 +00001021 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001022 {
cristye04362f2012-04-23 15:33:05 +00001023 /*
1024 Set remaining rows as undefined.
1025 */
cristy888e6132012-04-23 19:54:54 +00001026 length=clone_info->metacontent_extent;
1027 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1028 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001029 {
cristy888e6132012-04-23 19:54:54 +00001030 for (x=0; x < (ssize_t) clone_info->columns; x++)
1031 {
1032 if (clone_info->type != DiskCache)
1033 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1034 blob,length);
1035 else
1036 {
1037 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1038 blob);
1039 if ((MagickSizeType) count != length)
1040 {
1041 status=MagickFalse;
1042 break;
1043 }
1044 }
1045 clone_offset+=length;
1046 }
cristye04362f2012-04-23 15:33:05 +00001047 }
cristy4c08aed2011-07-01 19:47:50 +00001048 }
cristy4c08aed2011-07-01 19:47:50 +00001049 }
1050 if (clone_info->type == DiskCache)
1051 (void) ClosePixelCacheOnDisk(clone_info);
1052 if (cache_info->type == DiskCache)
1053 (void) ClosePixelCacheOnDisk(cache_info);
1054 blob=(unsigned char *) RelinquishMagickMemory(blob);
1055 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001056}
1057
1058static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1059 CacheInfo *cache_info,ExceptionInfo *exception)
1060{
cristy3dfccb22011-12-28 21:47:20 +00001061 PixelChannelMap
1062 *p,
1063 *q;
1064
cristy5a7fbfb2010-11-06 16:10:59 +00001065 if (cache_info->type == PingCache)
1066 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001067 p=cache_info->channel_map;
1068 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001069 if ((cache_info->columns == clone_info->columns) &&
1070 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001071 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001072 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001073 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001074 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1075 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001076}
1077
1078/*
1079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1080% %
1081% %
1082% %
1083+ C l o n e P i x e l C a c h e M e t h o d s %
1084% %
1085% %
1086% %
1087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088%
1089% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1090% another.
1091%
1092% The format of the ClonePixelCacheMethods() method is:
1093%
1094% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1095%
1096% A description of each parameter follows:
1097%
1098% o clone: Specifies a pointer to a Cache structure.
1099%
1100% o cache: the pixel cache.
1101%
1102*/
cristya6577ff2011-09-02 19:54:26 +00001103MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001104{
1105 CacheInfo
1106 *cache_info,
1107 *source_info;
1108
1109 assert(clone != (Cache) NULL);
1110 source_info=(CacheInfo *) clone;
1111 assert(source_info->signature == MagickSignature);
1112 if (source_info->debug != MagickFalse)
1113 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1114 source_info->filename);
1115 assert(cache != (Cache) NULL);
1116 cache_info=(CacheInfo *) cache;
1117 assert(cache_info->signature == MagickSignature);
1118 source_info->methods=cache_info->methods;
1119}
1120
1121/*
1122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1123% %
1124% %
1125% %
1126+ D e s t r o y I m a g e P i x e l C a c h e %
1127% %
1128% %
1129% %
1130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1131%
1132% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1133%
1134% The format of the DestroyImagePixelCache() method is:
1135%
1136% void DestroyImagePixelCache(Image *image)
1137%
1138% A description of each parameter follows:
1139%
1140% o image: the image.
1141%
1142*/
1143static void DestroyImagePixelCache(Image *image)
1144{
1145 assert(image != (Image *) NULL);
1146 assert(image->signature == MagickSignature);
1147 if (image->debug != MagickFalse)
1148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1149 if (image->cache == (void *) NULL)
1150 return;
1151 image->cache=DestroyPixelCache(image->cache);
1152}
1153
1154/*
1155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1156% %
1157% %
1158% %
1159+ D e s t r o y I m a g e P i x e l s %
1160% %
1161% %
1162% %
1163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1164%
1165% DestroyImagePixels() deallocates memory associated with the pixel cache.
1166%
1167% The format of the DestroyImagePixels() method is:
1168%
1169% void DestroyImagePixels(Image *image)
1170%
1171% A description of each parameter follows:
1172%
1173% o image: the image.
1174%
1175*/
1176MagickExport void DestroyImagePixels(Image *image)
1177{
1178 CacheInfo
1179 *cache_info;
1180
1181 assert(image != (const Image *) NULL);
1182 assert(image->signature == MagickSignature);
1183 if (image->debug != MagickFalse)
1184 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1185 assert(image->cache != (Cache) NULL);
1186 cache_info=(CacheInfo *) image->cache;
1187 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001188 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1189 {
1190 cache_info->methods.destroy_pixel_handler(image);
1191 return;
1192 }
cristy2036f5c2010-09-19 21:18:17 +00001193 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001194}
1195
1196/*
1197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198% %
1199% %
1200% %
1201+ D e s t r o y P i x e l C a c h e %
1202% %
1203% %
1204% %
1205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206%
1207% DestroyPixelCache() deallocates memory associated with the pixel cache.
1208%
1209% The format of the DestroyPixelCache() method is:
1210%
1211% Cache DestroyPixelCache(Cache cache)
1212%
1213% A description of each parameter follows:
1214%
1215% o cache: the pixel cache.
1216%
1217*/
1218
1219static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1220{
1221 switch (cache_info->type)
1222 {
1223 case MemoryCache:
1224 {
1225 if (cache_info->mapped == MagickFalse)
cristy9dd0b6f2012-08-01 14:38:43 +00001226 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
cristy3ed852e2009-09-05 21:47:34 +00001227 cache_info->pixels);
1228 else
cristy4c08aed2011-07-01 19:47:50 +00001229 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001230 (size_t) cache_info->length);
1231 RelinquishMagickResource(MemoryResource,cache_info->length);
1232 break;
1233 }
1234 case MapCache:
1235 {
cristy4c08aed2011-07-01 19:47:50 +00001236 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001237 cache_info->length);
1238 RelinquishMagickResource(MapResource,cache_info->length);
1239 }
1240 case DiskCache:
1241 {
1242 if (cache_info->file != -1)
1243 (void) ClosePixelCacheOnDisk(cache_info);
1244 RelinquishMagickResource(DiskResource,cache_info->length);
1245 break;
1246 }
1247 default:
1248 break;
1249 }
1250 cache_info->type=UndefinedCache;
1251 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001252 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001253}
1254
cristya6577ff2011-09-02 19:54:26 +00001255MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001256{
1257 CacheInfo
1258 *cache_info;
1259
cristy3ed852e2009-09-05 21:47:34 +00001260 assert(cache != (Cache) NULL);
1261 cache_info=(CacheInfo *) cache;
1262 assert(cache_info->signature == MagickSignature);
1263 if (cache_info->debug != MagickFalse)
1264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1265 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001266 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001267 cache_info->reference_count--;
1268 if (cache_info->reference_count != 0)
1269 {
cristyf84a1932010-01-03 18:00:18 +00001270 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001271 return((Cache) NULL);
1272 }
cristyf84a1932010-01-03 18:00:18 +00001273 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001274 if (cache_info->debug != MagickFalse)
1275 {
1276 char
1277 message[MaxTextExtent];
1278
cristyb51dff52011-05-19 16:55:47 +00001279 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001280 cache_info->filename);
1281 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1282 }
cristyc2e1bdd2009-09-10 23:43:34 +00001283 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1284 (cache_info->type != DiskCache)))
1285 RelinquishPixelCachePixels(cache_info);
1286 else
1287 {
1288 RelinquishPixelCachePixels(cache_info);
1289 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1290 }
cristy3ed852e2009-09-05 21:47:34 +00001291 *cache_info->cache_filename='\0';
1292 if (cache_info->nexus_info != (NexusInfo **) NULL)
1293 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1294 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001295 if (cache_info->random_info != (RandomInfo *) NULL)
1296 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001297 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1298 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1299 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1300 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001301 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001302 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001303 cache=(Cache) NULL;
1304 return(cache);
1305}
1306
1307/*
1308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309% %
1310% %
1311% %
1312+ D e s t r o y P i x e l C a c h e N e x u s %
1313% %
1314% %
1315% %
1316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1317%
1318% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1319%
1320% The format of the DestroyPixelCacheNexus() method is:
1321%
1322% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001323% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001324%
1325% A description of each parameter follows:
1326%
1327% o nexus_info: the nexus to destroy.
1328%
1329% o number_threads: the number of nexus threads.
1330%
1331*/
1332
1333static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1334{
1335 if (nexus_info->mapped == MagickFalse)
cristy9dd0b6f2012-08-01 14:38:43 +00001336 (void) RelinquishAlignedMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001337 else
1338 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001339 nexus_info->cache=(Quantum *) NULL;
1340 nexus_info->pixels=(Quantum *) NULL;
1341 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001342 nexus_info->length=0;
1343 nexus_info->mapped=MagickFalse;
1344}
1345
cristya6577ff2011-09-02 19:54:26 +00001346MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001347 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001348{
cristybb503372010-05-27 20:51:26 +00001349 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001350 i;
1351
1352 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001353 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001354 {
cristy4c08aed2011-07-01 19:47:50 +00001355 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001356 RelinquishCacheNexusPixels(nexus_info[i]);
1357 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001358 }
cristye5f87c82012-02-14 12:44:17 +00001359 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001360 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001361 return(nexus_info);
1362}
1363
1364/*
1365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366% %
1367% %
1368% %
cristy4c08aed2011-07-01 19:47:50 +00001369% 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 +00001370% %
1371% %
1372% %
1373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1374%
cristy4c08aed2011-07-01 19:47:50 +00001375% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1376% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1377% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001378%
cristy4c08aed2011-07-01 19:47:50 +00001379% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001380%
cristy4c08aed2011-07-01 19:47:50 +00001381% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001382%
1383% A description of each parameter follows:
1384%
1385% o image: the image.
1386%
1387*/
cristy4c08aed2011-07-01 19:47:50 +00001388MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001389{
1390 CacheInfo
1391 *cache_info;
1392
cristy5c9e6f22010-09-17 17:31:01 +00001393 const int
1394 id = GetOpenMPThreadId();
1395
cristy4c08aed2011-07-01 19:47:50 +00001396 void
1397 *metacontent;
1398
cristye7cc7cf2010-09-21 13:26:47 +00001399 assert(image != (const Image *) NULL);
1400 assert(image->signature == MagickSignature);
1401 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001402 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001403 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001404 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1405 (GetAuthenticMetacontentFromHandler) NULL)
1406 {
1407 metacontent=cache_info->methods.
1408 get_authentic_metacontent_from_handler(image);
1409 return(metacontent);
1410 }
cristy6ebe97c2010-07-03 01:17:28 +00001411 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001412 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1413 cache_info->nexus_info[id]);
1414 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001415}
1416
1417/*
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419% %
1420% %
1421% %
cristy4c08aed2011-07-01 19:47:50 +00001422+ 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 +00001423% %
1424% %
1425% %
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427%
cristy4c08aed2011-07-01 19:47:50 +00001428% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1429% with the last call to QueueAuthenticPixelsCache() or
1430% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001431%
cristy4c08aed2011-07-01 19:47:50 +00001432% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001433%
cristy4c08aed2011-07-01 19:47:50 +00001434% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001435%
1436% A description of each parameter follows:
1437%
1438% o image: the image.
1439%
1440*/
cristy4c08aed2011-07-01 19:47:50 +00001441static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001442{
1443 CacheInfo
1444 *cache_info;
1445
cristy2036f5c2010-09-19 21:18:17 +00001446 const int
1447 id = GetOpenMPThreadId();
1448
cristy4c08aed2011-07-01 19:47:50 +00001449 void
1450 *metacontent;
1451
cristy3ed852e2009-09-05 21:47:34 +00001452 assert(image != (const Image *) NULL);
1453 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001454 assert(image->cache != (Cache) NULL);
1455 cache_info=(CacheInfo *) image->cache;
1456 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001457 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001458 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1459 cache_info->nexus_info[id]);
1460 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001461}
1462
1463/*
1464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465% %
1466% %
1467% %
1468+ 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 %
1469% %
1470% %
1471% %
1472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1473%
1474% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1475% disk pixel cache as defined by the geometry parameters. A pointer to the
1476% pixels is returned if the pixels are transferred, otherwise a NULL is
1477% returned.
1478%
1479% The format of the GetAuthenticPixelCacheNexus() method is:
1480%
cristy4c08aed2011-07-01 19:47:50 +00001481% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001482% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001483% NexusInfo *nexus_info,ExceptionInfo *exception)
1484%
1485% A description of each parameter follows:
1486%
1487% o image: the image.
1488%
1489% o x,y,columns,rows: These values define the perimeter of a region of
1490% pixels.
1491%
1492% o nexus_info: the cache nexus to return.
1493%
1494% o exception: return any errors or warnings in this structure.
1495%
1496*/
1497
cristy7f69b802012-05-08 16:39:59 +00001498static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001499 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001500{
cristy4c08aed2011-07-01 19:47:50 +00001501 MagickBooleanType
1502 status;
1503
cristy3ed852e2009-09-05 21:47:34 +00001504 MagickOffsetType
1505 offset;
1506
cristy73724512010-04-12 14:43:14 +00001507 if (cache_info->type == PingCache)
1508 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001509 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1510 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001511 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001512 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001513 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001514}
1515
cristya6577ff2011-09-02 19:54:26 +00001516MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001517 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001518 NexusInfo *nexus_info,ExceptionInfo *exception)
1519{
1520 CacheInfo
1521 *cache_info;
1522
cristy4c08aed2011-07-01 19:47:50 +00001523 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001524 *q;
cristy3ed852e2009-09-05 21:47:34 +00001525
1526 /*
1527 Transfer pixels from the cache.
1528 */
1529 assert(image != (Image *) NULL);
1530 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001531 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1532 exception);
cristyacd2ed22011-08-30 01:44:23 +00001533 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001534 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001535 cache_info=(CacheInfo *) image->cache;
1536 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001537 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001538 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001539 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001540 return((Quantum *) NULL);
1541 if (cache_info->metacontent_extent != 0)
1542 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1543 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001544 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001545}
1546
1547/*
1548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1549% %
1550% %
1551% %
1552+ 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 %
1553% %
1554% %
1555% %
1556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1557%
1558% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1559% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1560%
1561% The format of the GetAuthenticPixelsFromCache() method is:
1562%
cristy4c08aed2011-07-01 19:47:50 +00001563% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001564%
1565% A description of each parameter follows:
1566%
1567% o image: the image.
1568%
1569*/
cristy4c08aed2011-07-01 19:47:50 +00001570static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001571{
1572 CacheInfo
1573 *cache_info;
1574
cristy5c9e6f22010-09-17 17:31:01 +00001575 const int
1576 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001577
cristye7cc7cf2010-09-21 13:26:47 +00001578 assert(image != (const Image *) NULL);
1579 assert(image->signature == MagickSignature);
1580 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001581 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001582 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001583 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001584 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001585}
1586
1587/*
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589% %
1590% %
1591% %
1592% G e t A u t h e n t i c P i x e l Q u e u e %
1593% %
1594% %
1595% %
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597%
cristy4c08aed2011-07-01 19:47:50 +00001598% GetAuthenticPixelQueue() returns the authentic pixels associated
1599% corresponding with the last call to QueueAuthenticPixels() or
1600% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001601%
1602% The format of the GetAuthenticPixelQueue() method is:
1603%
cristy4c08aed2011-07-01 19:47:50 +00001604% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001605%
1606% A description of each parameter follows:
1607%
1608% o image: the image.
1609%
1610*/
cristy4c08aed2011-07-01 19:47:50 +00001611MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001612{
1613 CacheInfo
1614 *cache_info;
1615
cristy2036f5c2010-09-19 21:18:17 +00001616 const int
1617 id = GetOpenMPThreadId();
1618
cristy3ed852e2009-09-05 21:47:34 +00001619 assert(image != (const Image *) NULL);
1620 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001621 assert(image->cache != (Cache) NULL);
1622 cache_info=(CacheInfo *) image->cache;
1623 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001624 if (cache_info->methods.get_authentic_pixels_from_handler !=
1625 (GetAuthenticPixelsFromHandler) NULL)
1626 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001627 assert(id < (int) cache_info->number_threads);
1628 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001629}
1630
1631/*
1632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633% %
1634% %
1635% %
1636% G e t A u t h e n t i c P i x e l s %
1637% %
1638% %
cristy4c08aed2011-07-01 19:47:50 +00001639% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001640%
1641% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001642% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001643% representing the region is returned, otherwise NULL is returned.
1644%
1645% The returned pointer may point to a temporary working copy of the pixels
1646% or it may point to the original pixels in memory. Performance is maximized
1647% if the selected region is part of one row, or one or more full rows, since
1648% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001649% if the image is in memory, or in a memory-mapped file. The returned pointer
1650% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001651%
1652% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001653% Quantum. If the image has corresponding metacontent,call
1654% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1655% meta-content corresponding to the region. Once the Quantum array has
1656% been updated, the changes must be saved back to the underlying image using
1657% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001658%
1659% The format of the GetAuthenticPixels() method is:
1660%
cristy4c08aed2011-07-01 19:47:50 +00001661% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001662% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001663% ExceptionInfo *exception)
1664%
1665% A description of each parameter follows:
1666%
1667% o image: the image.
1668%
1669% o x,y,columns,rows: These values define the perimeter of a region of
1670% pixels.
1671%
1672% o exception: return any errors or warnings in this structure.
1673%
1674*/
cristy4c08aed2011-07-01 19:47:50 +00001675MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001676 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001677 ExceptionInfo *exception)
1678{
1679 CacheInfo
1680 *cache_info;
1681
cristy2036f5c2010-09-19 21:18:17 +00001682 const int
1683 id = GetOpenMPThreadId();
1684
cristy4c08aed2011-07-01 19:47:50 +00001685 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001686 *q;
cristy4c08aed2011-07-01 19:47:50 +00001687
cristy3ed852e2009-09-05 21:47:34 +00001688 assert(image != (Image *) NULL);
1689 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001690 assert(image->cache != (Cache) NULL);
1691 cache_info=(CacheInfo *) image->cache;
1692 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001693 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001694 (GetAuthenticPixelsHandler) NULL)
1695 {
cristyacd2ed22011-08-30 01:44:23 +00001696 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1697 exception);
1698 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001699 }
cristy2036f5c2010-09-19 21:18:17 +00001700 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001701 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001702 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001703 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001704}
1705
1706/*
1707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1708% %
1709% %
1710% %
1711+ G e t A u t h e n t i c P i x e l s C a c h e %
1712% %
1713% %
1714% %
1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716%
1717% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1718% as defined by the geometry parameters. A pointer to the pixels is returned
1719% if the pixels are transferred, otherwise a NULL is returned.
1720%
1721% The format of the GetAuthenticPixelsCache() method is:
1722%
cristy4c08aed2011-07-01 19:47:50 +00001723% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001724% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001725% ExceptionInfo *exception)
1726%
1727% A description of each parameter follows:
1728%
1729% o image: the image.
1730%
1731% o x,y,columns,rows: These values define the perimeter of a region of
1732% pixels.
1733%
1734% o exception: return any errors or warnings in this structure.
1735%
1736*/
cristy4c08aed2011-07-01 19:47:50 +00001737static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001738 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001739 ExceptionInfo *exception)
1740{
1741 CacheInfo
1742 *cache_info;
1743
cristy5c9e6f22010-09-17 17:31:01 +00001744 const int
1745 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001746
cristy4c08aed2011-07-01 19:47:50 +00001747 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001748 *q;
cristy4c08aed2011-07-01 19:47:50 +00001749
cristye7cc7cf2010-09-21 13:26:47 +00001750 assert(image != (const Image *) NULL);
1751 assert(image->signature == MagickSignature);
1752 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001753 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001754 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001755 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001756 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001757 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001758 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001759 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001760 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001761}
1762
1763/*
1764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765% %
1766% %
1767% %
1768+ G e t I m a g e E x t e n t %
1769% %
1770% %
1771% %
1772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1773%
cristy4c08aed2011-07-01 19:47:50 +00001774% GetImageExtent() returns the extent of the pixels associated corresponding
1775% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001776%
1777% The format of the GetImageExtent() method is:
1778%
1779% MagickSizeType GetImageExtent(const Image *image)
1780%
1781% A description of each parameter follows:
1782%
1783% o image: the image.
1784%
1785*/
1786MagickExport MagickSizeType GetImageExtent(const Image *image)
1787{
1788 CacheInfo
1789 *cache_info;
1790
cristy5c9e6f22010-09-17 17:31:01 +00001791 const int
1792 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001793
cristy3ed852e2009-09-05 21:47:34 +00001794 assert(image != (Image *) NULL);
1795 assert(image->signature == MagickSignature);
1796 if (image->debug != MagickFalse)
1797 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1798 assert(image->cache != (Cache) NULL);
1799 cache_info=(CacheInfo *) image->cache;
1800 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001801 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001802 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001803}
1804
1805/*
1806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807% %
1808% %
1809% %
1810+ G e t I m a g e P i x e l C a c h e %
1811% %
1812% %
1813% %
1814%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1815%
1816% GetImagePixelCache() ensures that there is only a single reference to the
1817% pixel cache to be modified, updating the provided cache pointer to point to
1818% a clone of the original pixel cache if necessary.
1819%
1820% The format of the GetImagePixelCache method is:
1821%
1822% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1823% ExceptionInfo *exception)
1824%
1825% A description of each parameter follows:
1826%
1827% o image: the image.
1828%
1829% o clone: any value other than MagickFalse clones the cache pixels.
1830%
1831% o exception: return any errors or warnings in this structure.
1832%
1833*/
cristyaf894d72011-08-06 23:03:10 +00001834
cristyf1832792012-05-08 18:38:18 +00001835static inline MagickBooleanType ValidatePixelCacheMorphology(
1836 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001837{
cristyf1832792012-05-08 18:38:18 +00001838 const CacheInfo
1839 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001840
cristyf1832792012-05-08 18:38:18 +00001841 const PixelChannelMap
1842 *restrict p,
1843 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001844
cristy3ed852e2009-09-05 21:47:34 +00001845 /*
1846 Does the image match the pixel cache morphology?
1847 */
1848 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001849 p=image->channel_map;
1850 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001851 if ((image->storage_class != cache_info->storage_class) ||
1852 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001853 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001854 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001855 (image->columns != cache_info->columns) ||
1856 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001857 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001858 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001859 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001860 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001861 return(MagickFalse);
1862 return(MagickTrue);
1863}
1864
cristycd01fae2011-08-06 23:52:42 +00001865static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1866 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001867{
1868 CacheInfo
1869 *cache_info;
1870
cristy3ed852e2009-09-05 21:47:34 +00001871 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001872 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001873 status;
1874
cristy50a10922010-02-15 18:35:25 +00001875 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001876 cpu_throttle = 0,
1877 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001878 time_limit = 0;
1879
cristy1ea34962010-07-01 19:49:21 +00001880 static time_t
cristy208b1002011-08-07 18:51:50 +00001881 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001882
cristyc4f9f132010-03-04 18:50:01 +00001883 status=MagickTrue;
1884 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001885 if (cpu_throttle == 0)
1886 {
1887 char
1888 *limit;
1889
1890 /*
1891 Set CPU throttle in milleseconds.
1892 */
1893 cpu_throttle=MagickResourceInfinity;
1894 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1895 if (limit == (char *) NULL)
1896 limit=GetPolicyValue("throttle");
1897 if (limit != (char *) NULL)
1898 {
1899 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1900 limit=DestroyString(limit);
1901 }
1902 }
1903 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1904 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001905 if (time_limit == 0)
1906 {
cristy6ebe97c2010-07-03 01:17:28 +00001907 /*
1908 Set the exire time in seconds.
1909 */
cristy1ea34962010-07-01 19:49:21 +00001910 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001911 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001912 }
1913 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001914 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001915 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001916 assert(image->cache != (Cache) NULL);
1917 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001918 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +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 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001922 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001923 {
cristyceb55ee2010-11-06 16:05:49 +00001924 Image
1925 clone_image;
1926
1927 CacheInfo
1928 *clone_info;
1929
1930 /*
1931 Clone pixel cache.
1932 */
1933 clone_image=(*image);
1934 clone_image.semaphore=AllocateSemaphoreInfo();
1935 clone_image.reference_count=1;
1936 clone_image.cache=ClonePixelCache(cache_info);
1937 clone_info=(CacheInfo *) clone_image.cache;
1938 status=OpenPixelCache(&clone_image,IOMode,exception);
1939 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001940 {
cristy5a7fbfb2010-11-06 16:10:59 +00001941 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001942 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001943 if (status != MagickFalse)
1944 {
cristy979bf772011-08-08 00:04:15 +00001945 if (cache_info->mode == ReadMode)
1946 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001947 destroy=MagickTrue;
1948 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001949 }
1950 }
cristyceb55ee2010-11-06 16:05:49 +00001951 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001952 }
cristyceb55ee2010-11-06 16:05:49 +00001953 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001954 }
cristy4320e0e2009-09-10 15:00:08 +00001955 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001956 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001957 if (status != MagickFalse)
1958 {
1959 /*
1960 Ensure the image matches the pixel cache morphology.
1961 */
1962 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001963 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001964 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001965 {
1966 status=OpenPixelCache(image,IOMode,exception);
1967 cache_info=(CacheInfo *) image->cache;
1968 if (cache_info->type == DiskCache)
1969 (void) ClosePixelCacheOnDisk(cache_info);
1970 }
cristy3ed852e2009-09-05 21:47:34 +00001971 }
cristyf84a1932010-01-03 18:00:18 +00001972 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001973 if (status == MagickFalse)
1974 return((Cache) NULL);
1975 return(image->cache);
1976}
1977
1978/*
1979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980% %
1981% %
1982% %
cristyce1fe792012-05-16 15:58:37 +00001983+ G e t I m a g e P i x e l C a c h e T y p e %
1984% %
1985% %
1986% %
1987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988%
1989% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1990% DiskCache, MemoryCache, MapCache, or PingCache.
1991%
1992% The format of the GetImagePixelCacheType() method is:
1993%
cristy5bef4cd2012-05-17 18:08:56 +00001994% CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001995%
1996% A description of each parameter follows:
1997%
1998% o image: the image.
1999%
2000*/
cristy5bef4cd2012-05-17 18:08:56 +00002001MagickExport CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00002002{
cristy238287d2012-05-17 18:16:56 +00002003 CacheInfo
2004 *cache_info;
2005
2006 assert(image != (Image *) NULL);
2007 assert(image->signature == MagickSignature);
2008 assert(image->cache != (Cache) NULL);
2009 cache_info=(CacheInfo *) image->cache;
2010 assert(cache_info->signature == MagickSignature);
2011 return(cache_info->type);
cristyce1fe792012-05-16 15:58:37 +00002012}
2013
2014/*
2015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2016% %
2017% %
2018% %
cristy3ed852e2009-09-05 21:47:34 +00002019% G e t O n e A u t h e n t i c P i x e l %
2020% %
2021% %
2022% %
2023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2024%
2025% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2026% location. The image background color is returned if an error occurs.
2027%
2028% The format of the GetOneAuthenticPixel() method is:
2029%
cristybb503372010-05-27 20:51:26 +00002030% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002031% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002032%
2033% A description of each parameter follows:
2034%
2035% o image: the image.
2036%
2037% o x,y: These values define the location of the pixel to return.
2038%
2039% o pixel: return a pixel at the specified (x,y) location.
2040%
2041% o exception: return any errors or warnings in this structure.
2042%
2043*/
cristyacbbb7c2010-06-30 18:56:48 +00002044MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002045 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002046{
2047 CacheInfo
2048 *cache_info;
2049
cristy4c08aed2011-07-01 19:47:50 +00002050 register Quantum
2051 *q;
cristy2036f5c2010-09-19 21:18:17 +00002052
cristy2ed42f62011-10-02 19:49:57 +00002053 register ssize_t
2054 i;
2055
cristy3ed852e2009-09-05 21:47:34 +00002056 assert(image != (Image *) NULL);
2057 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002058 assert(image->cache != (Cache) NULL);
2059 cache_info=(CacheInfo *) image->cache;
2060 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002061 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002062 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2063 (GetOneAuthenticPixelFromHandler) NULL)
2064 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2065 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002066 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2067 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002068 {
cristy9e0719b2011-12-29 03:45:45 +00002069 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2070 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2071 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2072 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2073 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002074 return(MagickFalse);
2075 }
2076 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2077 {
2078 PixelChannel
2079 channel;
2080
cristye2a912b2011-12-05 20:02:07 +00002081 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002082 pixel[channel]=q[i];
2083 }
cristy2036f5c2010-09-19 21:18:17 +00002084 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002085}
2086
2087/*
2088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2089% %
2090% %
2091% %
2092+ 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 %
2093% %
2094% %
2095% %
2096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2097%
2098% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2099% location. The image background color is returned if an error occurs.
2100%
2101% The format of the GetOneAuthenticPixelFromCache() method is:
2102%
2103% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002104% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002105% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002106%
2107% A description of each parameter follows:
2108%
2109% o image: the image.
2110%
2111% o x,y: These values define the location of the pixel to return.
2112%
2113% o pixel: return a pixel at the specified (x,y) location.
2114%
2115% o exception: return any errors or warnings in this structure.
2116%
2117*/
2118static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002119 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002120{
cristy098f78c2010-09-23 17:28:44 +00002121 CacheInfo
2122 *cache_info;
2123
2124 const int
2125 id = GetOpenMPThreadId();
2126
cristy4c08aed2011-07-01 19:47:50 +00002127 register Quantum
2128 *q;
cristy3ed852e2009-09-05 21:47:34 +00002129
cristy2ed42f62011-10-02 19:49:57 +00002130 register ssize_t
2131 i;
2132
cristy0158a4b2010-09-20 13:59:45 +00002133 assert(image != (const Image *) NULL);
2134 assert(image->signature == MagickSignature);
2135 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002136 cache_info=(CacheInfo *) image->cache;
2137 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002138 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002139 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002140 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2141 exception);
2142 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002143 {
cristy9e0719b2011-12-29 03:45:45 +00002144 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2145 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2146 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2147 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2148 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002149 return(MagickFalse);
2150 }
2151 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2152 {
2153 PixelChannel
2154 channel;
2155
cristye2a912b2011-12-05 20:02:07 +00002156 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002157 pixel[channel]=q[i];
2158 }
cristy3ed852e2009-09-05 21:47:34 +00002159 return(MagickTrue);
2160}
2161
2162/*
2163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164% %
2165% %
2166% %
cristy3ed852e2009-09-05 21:47:34 +00002167% G e t O n e V i r t u a l P i x e l %
2168% %
2169% %
2170% %
2171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2172%
2173% GetOneVirtualPixel() returns a single virtual pixel at the specified
2174% (x,y) location. The image background color is returned if an error occurs.
2175% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2176%
2177% The format of the GetOneVirtualPixel() method is:
2178%
cristybb503372010-05-27 20:51:26 +00002179% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002180% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002181%
2182% A description of each parameter follows:
2183%
2184% o image: the image.
2185%
2186% o x,y: These values define the location of the pixel to return.
2187%
2188% o pixel: return a pixel at the specified (x,y) location.
2189%
2190% o exception: return any errors or warnings in this structure.
2191%
2192*/
2193MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002194 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002195{
cristy3ed852e2009-09-05 21:47:34 +00002196 CacheInfo
2197 *cache_info;
2198
cristy0158a4b2010-09-20 13:59:45 +00002199 const int
2200 id = GetOpenMPThreadId();
2201
cristy4c08aed2011-07-01 19:47:50 +00002202 const Quantum
2203 *p;
cristy2036f5c2010-09-19 21:18:17 +00002204
cristy2ed42f62011-10-02 19:49:57 +00002205 register ssize_t
2206 i;
2207
cristy3ed852e2009-09-05 21:47:34 +00002208 assert(image != (const Image *) NULL);
2209 assert(image->signature == MagickSignature);
2210 assert(image->cache != (Cache) NULL);
2211 cache_info=(CacheInfo *) image->cache;
2212 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002213 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002214 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2215 (GetOneVirtualPixelFromHandler) NULL)
2216 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2217 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002218 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002219 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002220 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002221 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002222 {
cristy9e0719b2011-12-29 03:45:45 +00002223 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2224 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2225 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2226 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2227 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002228 return(MagickFalse);
2229 }
2230 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2231 {
2232 PixelChannel
2233 channel;
2234
cristye2a912b2011-12-05 20:02:07 +00002235 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002236 pixel[channel]=p[i];
2237 }
cristy2036f5c2010-09-19 21:18:17 +00002238 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002239}
2240
2241/*
2242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243% %
2244% %
2245% %
2246+ 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 %
2247% %
2248% %
2249% %
2250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2251%
2252% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2253% specified (x,y) location. The image background color is returned if an
2254% error occurs.
2255%
2256% The format of the GetOneVirtualPixelFromCache() method is:
2257%
2258% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002259% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002260% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002261%
2262% A description of each parameter follows:
2263%
2264% o image: the image.
2265%
2266% o virtual_pixel_method: the virtual pixel method.
2267%
2268% o x,y: These values define the location of the pixel to return.
2269%
2270% o pixel: return a pixel at the specified (x,y) location.
2271%
2272% o exception: return any errors or warnings in this structure.
2273%
2274*/
2275static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002276 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002277 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002278{
cristy0158a4b2010-09-20 13:59:45 +00002279 CacheInfo
2280 *cache_info;
2281
2282 const int
2283 id = GetOpenMPThreadId();
2284
cristy4c08aed2011-07-01 19:47:50 +00002285 const Quantum
2286 *p;
cristy3ed852e2009-09-05 21:47:34 +00002287
cristy2ed42f62011-10-02 19:49:57 +00002288 register ssize_t
2289 i;
2290
cristye7cc7cf2010-09-21 13:26:47 +00002291 assert(image != (const Image *) NULL);
2292 assert(image->signature == MagickSignature);
2293 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002294 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002295 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002296 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002297 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002298 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002299 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002300 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002301 {
cristy9e0719b2011-12-29 03:45:45 +00002302 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2303 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2304 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2305 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2306 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002307 return(MagickFalse);
2308 }
2309 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2310 {
2311 PixelChannel
2312 channel;
2313
cristye2a912b2011-12-05 20:02:07 +00002314 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002315 pixel[channel]=p[i];
2316 }
cristy3ed852e2009-09-05 21:47:34 +00002317 return(MagickTrue);
2318}
2319
2320/*
2321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2322% %
2323% %
2324% %
cristy3aa93752011-12-18 15:54:24 +00002325% G e t O n e V i r t u a l P i x e l I n f o %
2326% %
2327% %
2328% %
2329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2330%
2331% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2332% location. The image background color is returned if an error occurs. If
2333% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2334%
2335% The format of the GetOneVirtualPixelInfo() method is:
2336%
2337% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2338% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2339% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2340%
2341% A description of each parameter follows:
2342%
2343% o image: the image.
2344%
2345% o virtual_pixel_method: the virtual pixel method.
2346%
2347% o x,y: these values define the location of the pixel to return.
2348%
2349% o pixel: return a pixel at the specified (x,y) location.
2350%
2351% o exception: return any errors or warnings in this structure.
2352%
2353*/
2354MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2355 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2356 PixelInfo *pixel,ExceptionInfo *exception)
2357{
2358 CacheInfo
2359 *cache_info;
2360
2361 const int
2362 id = GetOpenMPThreadId();
2363
2364 register const Quantum
2365 *p;
2366
2367 assert(image != (const Image *) NULL);
2368 assert(image->signature == MagickSignature);
2369 assert(image->cache != (Cache) NULL);
2370 cache_info=(CacheInfo *) image->cache;
2371 assert(cache_info->signature == MagickSignature);
2372 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002373 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002374 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2375 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002376 if (p == (const Quantum *) NULL)
2377 return(MagickFalse);
2378 GetPixelInfoPixel(image,p,pixel);
2379 return(MagickTrue);
2380}
2381
2382/*
2383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2384% %
2385% %
2386% %
cristy3ed852e2009-09-05 21:47:34 +00002387+ G e t P i x e l C a c h e C o l o r s p a c e %
2388% %
2389% %
2390% %
2391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2392%
2393% GetPixelCacheColorspace() returns the class type of the pixel cache.
2394%
2395% The format of the GetPixelCacheColorspace() method is:
2396%
2397% Colorspace GetPixelCacheColorspace(Cache cache)
2398%
2399% A description of each parameter follows:
2400%
2401% o cache: the pixel cache.
2402%
2403*/
cristya6577ff2011-09-02 19:54:26 +00002404MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002405{
2406 CacheInfo
2407 *cache_info;
2408
2409 assert(cache != (Cache) NULL);
2410 cache_info=(CacheInfo *) cache;
2411 assert(cache_info->signature == MagickSignature);
2412 if (cache_info->debug != MagickFalse)
2413 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2414 cache_info->filename);
2415 return(cache_info->colorspace);
2416}
2417
2418/*
2419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2420% %
2421% %
2422% %
2423+ G e t P i x e l C a c h e M e t h o d s %
2424% %
2425% %
2426% %
2427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2428%
2429% GetPixelCacheMethods() initializes the CacheMethods structure.
2430%
2431% The format of the GetPixelCacheMethods() method is:
2432%
2433% void GetPixelCacheMethods(CacheMethods *cache_methods)
2434%
2435% A description of each parameter follows:
2436%
2437% o cache_methods: Specifies a pointer to a CacheMethods structure.
2438%
2439*/
cristya6577ff2011-09-02 19:54:26 +00002440MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002441{
2442 assert(cache_methods != (CacheMethods *) NULL);
2443 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2444 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2445 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002446 cache_methods->get_virtual_metacontent_from_handler=
2447 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002448 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2449 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002450 cache_methods->get_authentic_metacontent_from_handler=
2451 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002452 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2453 cache_methods->get_one_authentic_pixel_from_handler=
2454 GetOneAuthenticPixelFromCache;
2455 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2456 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2457 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2458}
2459
2460/*
2461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462% %
2463% %
2464% %
2465+ G e t P i x e l C a c h e N e x u s E x t e n t %
2466% %
2467% %
2468% %
2469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2470%
cristy4c08aed2011-07-01 19:47:50 +00002471% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2472% corresponding with the last call to SetPixelCacheNexusPixels() or
2473% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002474%
2475% The format of the GetPixelCacheNexusExtent() method is:
2476%
2477% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2478% NexusInfo *nexus_info)
2479%
2480% A description of each parameter follows:
2481%
2482% o nexus_info: the nexus info.
2483%
2484*/
cristya6577ff2011-09-02 19:54:26 +00002485MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002486 NexusInfo *nexus_info)
2487{
2488 CacheInfo
2489 *cache_info;
2490
2491 MagickSizeType
2492 extent;
2493
cristy9f027d12011-09-21 01:17:17 +00002494 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002495 cache_info=(CacheInfo *) cache;
2496 assert(cache_info->signature == MagickSignature);
2497 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2498 if (extent == 0)
2499 return((MagickSizeType) cache_info->columns*cache_info->rows);
2500 return(extent);
2501}
2502
2503/*
2504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2505% %
2506% %
2507% %
cristy4c08aed2011-07-01 19:47:50 +00002508+ 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 +00002509% %
2510% %
2511% %
2512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2513%
cristy4c08aed2011-07-01 19:47:50 +00002514% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2515% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002516%
cristy4c08aed2011-07-01 19:47:50 +00002517% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002518%
cristy4c08aed2011-07-01 19:47:50 +00002519% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002520% NexusInfo *nexus_info)
2521%
2522% A description of each parameter follows:
2523%
2524% o cache: the pixel cache.
2525%
cristy4c08aed2011-07-01 19:47:50 +00002526% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002527%
2528*/
cristya6577ff2011-09-02 19:54:26 +00002529MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002530 NexusInfo *nexus_info)
2531{
2532 CacheInfo
2533 *cache_info;
2534
cristy9f027d12011-09-21 01:17:17 +00002535 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002536 cache_info=(CacheInfo *) cache;
2537 assert(cache_info->signature == MagickSignature);
2538 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002539 return((void *) NULL);
2540 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002541}
2542
2543/*
2544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2545% %
2546% %
2547% %
2548+ G e t P i x e l C a c h e N e x u s P i x e l s %
2549% %
2550% %
2551% %
2552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2553%
2554% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2555% cache nexus.
2556%
2557% The format of the GetPixelCacheNexusPixels() method is:
2558%
cristy4c08aed2011-07-01 19:47:50 +00002559% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002560% NexusInfo *nexus_info)
2561%
2562% A description of each parameter follows:
2563%
2564% o cache: the pixel cache.
2565%
2566% o nexus_info: the cache nexus to return the pixels.
2567%
2568*/
cristya6577ff2011-09-02 19:54:26 +00002569MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002570 NexusInfo *nexus_info)
2571{
2572 CacheInfo
2573 *cache_info;
2574
cristy9f027d12011-09-21 01:17:17 +00002575 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002576 cache_info=(CacheInfo *) cache;
2577 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002578 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002579 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002580 return(nexus_info->pixels);
2581}
2582
2583/*
2584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585% %
2586% %
2587% %
cristy056ba772010-01-02 23:33:54 +00002588+ G e t P i x e l C a c h e P i x e l s %
2589% %
2590% %
2591% %
2592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2593%
2594% GetPixelCachePixels() returns the pixels associated with the specified image.
2595%
2596% The format of the GetPixelCachePixels() method is:
2597%
cristyf84a1932010-01-03 18:00:18 +00002598% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2599% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002600%
2601% A description of each parameter follows:
2602%
2603% o image: the image.
2604%
2605% o length: the pixel cache length.
2606%
cristyf84a1932010-01-03 18:00:18 +00002607% o exception: return any errors or warnings in this structure.
2608%
cristy056ba772010-01-02 23:33:54 +00002609*/
cristyd1dd6e42011-09-04 01:46:08 +00002610MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002611 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002612{
2613 CacheInfo
2614 *cache_info;
2615
2616 assert(image != (const Image *) NULL);
2617 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002618 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002619 assert(length != (MagickSizeType *) NULL);
2620 assert(exception != (ExceptionInfo *) NULL);
2621 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002622 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002623 assert(cache_info->signature == MagickSignature);
2624 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002625 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002626 return((void *) NULL);
2627 *length=cache_info->length;
2628 return((void *) cache_info->pixels);
2629}
2630
2631/*
2632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633% %
2634% %
2635% %
cristyb32b90a2009-09-07 21:45:48 +00002636+ 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 +00002637% %
2638% %
2639% %
2640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2641%
2642% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2643%
2644% The format of the GetPixelCacheStorageClass() method is:
2645%
2646% ClassType GetPixelCacheStorageClass(Cache cache)
2647%
2648% A description of each parameter follows:
2649%
2650% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2651%
2652% o cache: the pixel cache.
2653%
2654*/
cristya6577ff2011-09-02 19:54:26 +00002655MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002656{
2657 CacheInfo
2658 *cache_info;
2659
2660 assert(cache != (Cache) NULL);
2661 cache_info=(CacheInfo *) cache;
2662 assert(cache_info->signature == MagickSignature);
2663 if (cache_info->debug != MagickFalse)
2664 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2665 cache_info->filename);
2666 return(cache_info->storage_class);
2667}
2668
2669/*
2670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671% %
2672% %
2673% %
cristyb32b90a2009-09-07 21:45:48 +00002674+ G e t P i x e l C a c h e T i l e S i z e %
2675% %
2676% %
2677% %
2678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2679%
2680% GetPixelCacheTileSize() returns the pixel cache tile size.
2681%
2682% The format of the GetPixelCacheTileSize() method is:
2683%
cristybb503372010-05-27 20:51:26 +00002684% void GetPixelCacheTileSize(const Image *image,size_t *width,
2685% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002686%
2687% A description of each parameter follows:
2688%
2689% o image: the image.
2690%
2691% o width: the optimize cache tile width in pixels.
2692%
2693% o height: the optimize cache tile height in pixels.
2694%
2695*/
cristya6577ff2011-09-02 19:54:26 +00002696MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002697 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002698{
cristy4c08aed2011-07-01 19:47:50 +00002699 CacheInfo
2700 *cache_info;
2701
cristyb32b90a2009-09-07 21:45:48 +00002702 assert(image != (Image *) NULL);
2703 assert(image->signature == MagickSignature);
2704 if (image->debug != MagickFalse)
2705 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002706 cache_info=(CacheInfo *) image->cache;
2707 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002708 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristy238287d2012-05-17 18:16:56 +00002709 if (GetImagePixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002710 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002711 *height=(*width);
2712}
2713
2714/*
2715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716% %
2717% %
2718% %
cristy3ed852e2009-09-05 21:47:34 +00002719+ 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 %
2720% %
2721% %
2722% %
2723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2724%
2725% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2726% pixel cache. A virtual pixel is any pixel access that is outside the
2727% boundaries of the image cache.
2728%
2729% The format of the GetPixelCacheVirtualMethod() method is:
2730%
2731% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2732%
2733% A description of each parameter follows:
2734%
2735% o image: the image.
2736%
2737*/
cristyd1dd6e42011-09-04 01:46:08 +00002738MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002739{
2740 CacheInfo
2741 *cache_info;
2742
2743 assert(image != (Image *) NULL);
2744 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002745 assert(image->cache != (Cache) NULL);
2746 cache_info=(CacheInfo *) image->cache;
2747 assert(cache_info->signature == MagickSignature);
2748 return(cache_info->virtual_pixel_method);
2749}
2750
2751/*
2752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2753% %
2754% %
2755% %
cristy4c08aed2011-07-01 19:47:50 +00002756+ 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 +00002757% %
2758% %
2759% %
2760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2761%
cristy4c08aed2011-07-01 19:47:50 +00002762% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2763% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002764%
cristy4c08aed2011-07-01 19:47:50 +00002765% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002766%
cristy4c08aed2011-07-01 19:47:50 +00002767% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002768%
2769% A description of each parameter follows:
2770%
2771% o image: the image.
2772%
2773*/
cristy4c08aed2011-07-01 19:47:50 +00002774static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002775{
2776 CacheInfo
2777 *cache_info;
2778
cristy5c9e6f22010-09-17 17:31:01 +00002779 const int
2780 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002781
cristy4c08aed2011-07-01 19:47:50 +00002782 const void
2783 *metacontent;
2784
cristye7cc7cf2010-09-21 13:26:47 +00002785 assert(image != (const Image *) NULL);
2786 assert(image->signature == MagickSignature);
2787 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002788 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002789 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002790 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002791 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2792 cache_info->nexus_info[id]);
2793 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002794}
2795
2796/*
2797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2798% %
2799% %
2800% %
cristy4c08aed2011-07-01 19:47:50 +00002801+ 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 +00002802% %
2803% %
2804% %
2805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2806%
cristy4c08aed2011-07-01 19:47:50 +00002807% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2808% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002809%
cristy4c08aed2011-07-01 19:47:50 +00002810% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002811%
cristy4c08aed2011-07-01 19:47:50 +00002812% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002813% NexusInfo *nexus_info)
2814%
2815% A description of each parameter follows:
2816%
2817% o cache: the pixel cache.
2818%
cristy4c08aed2011-07-01 19:47:50 +00002819% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002820%
2821*/
cristya6577ff2011-09-02 19:54:26 +00002822MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002823 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002824{
2825 CacheInfo
2826 *cache_info;
2827
cristye7cc7cf2010-09-21 13:26:47 +00002828 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002829 cache_info=(CacheInfo *) cache;
2830 assert(cache_info->signature == MagickSignature);
2831 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002832 return((void *) NULL);
2833 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002834}
2835
2836/*
2837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838% %
2839% %
2840% %
cristy4c08aed2011-07-01 19:47:50 +00002841% 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 +00002842% %
2843% %
2844% %
2845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2846%
cristy4c08aed2011-07-01 19:47:50 +00002847% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2848% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2849% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002850%
cristy4c08aed2011-07-01 19:47:50 +00002851% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002852%
cristy4c08aed2011-07-01 19:47:50 +00002853% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002854%
2855% A description of each parameter follows:
2856%
2857% o image: the image.
2858%
2859*/
cristy4c08aed2011-07-01 19:47:50 +00002860MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002861{
2862 CacheInfo
2863 *cache_info;
2864
cristy2036f5c2010-09-19 21:18:17 +00002865 const int
2866 id = GetOpenMPThreadId();
2867
cristy4c08aed2011-07-01 19:47:50 +00002868 const void
2869 *metacontent;
2870
cristy3ed852e2009-09-05 21:47:34 +00002871 assert(image != (const Image *) NULL);
2872 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002873 assert(image->cache != (Cache) NULL);
2874 cache_info=(CacheInfo *) image->cache;
2875 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002876 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002877 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002878 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002879 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002880 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2881 cache_info->nexus_info[id]);
2882 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002883}
2884
2885/*
2886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2887% %
2888% %
2889% %
2890+ 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 %
2891% %
2892% %
2893% %
2894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2895%
2896% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2897% pixel cache as defined by the geometry parameters. A pointer to the pixels
2898% is returned if the pixels are transferred, otherwise a NULL is returned.
2899%
2900% The format of the GetVirtualPixelsFromNexus() method is:
2901%
cristy4c08aed2011-07-01 19:47:50 +00002902% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002903% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002904% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2905% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002906%
2907% A description of each parameter follows:
2908%
2909% o image: the image.
2910%
2911% o virtual_pixel_method: the virtual pixel method.
2912%
2913% o x,y,columns,rows: These values define the perimeter of a region of
2914% pixels.
2915%
2916% o nexus_info: the cache nexus to acquire.
2917%
2918% o exception: return any errors or warnings in this structure.
2919%
2920*/
2921
cristybb503372010-05-27 20:51:26 +00002922static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002923 DitherMatrix[64] =
2924 {
2925 0, 48, 12, 60, 3, 51, 15, 63,
2926 32, 16, 44, 28, 35, 19, 47, 31,
2927 8, 56, 4, 52, 11, 59, 7, 55,
2928 40, 24, 36, 20, 43, 27, 39, 23,
2929 2, 50, 14, 62, 1, 49, 13, 61,
2930 34, 18, 46, 30, 33, 17, 45, 29,
2931 10, 58, 6, 54, 9, 57, 5, 53,
2932 42, 26, 38, 22, 41, 25, 37, 21
2933 };
2934
cristybb503372010-05-27 20:51:26 +00002935static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002936{
cristybb503372010-05-27 20:51:26 +00002937 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002938 index;
2939
2940 index=x+DitherMatrix[x & 0x07]-32L;
2941 if (index < 0L)
2942 return(0L);
cristybb503372010-05-27 20:51:26 +00002943 if (index >= (ssize_t) columns)
2944 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002945 return(index);
2946}
2947
cristybb503372010-05-27 20:51:26 +00002948static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002949{
cristybb503372010-05-27 20:51:26 +00002950 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002951 index;
2952
2953 index=y+DitherMatrix[y & 0x07]-32L;
2954 if (index < 0L)
2955 return(0L);
cristybb503372010-05-27 20:51:26 +00002956 if (index >= (ssize_t) rows)
2957 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002958 return(index);
2959}
2960
cristybb503372010-05-27 20:51:26 +00002961static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002962{
2963 if (x < 0L)
2964 return(0L);
cristybb503372010-05-27 20:51:26 +00002965 if (x >= (ssize_t) columns)
2966 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002967 return(x);
2968}
2969
cristybb503372010-05-27 20:51:26 +00002970static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002971{
2972 if (y < 0L)
2973 return(0L);
cristybb503372010-05-27 20:51:26 +00002974 if (y >= (ssize_t) rows)
2975 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002976 return(y);
2977}
2978
cristybb503372010-05-27 20:51:26 +00002979static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002980{
cristybb503372010-05-27 20:51:26 +00002981 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002982}
2983
cristybb503372010-05-27 20:51:26 +00002984static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002985{
cristybb503372010-05-27 20:51:26 +00002986 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002987}
2988
cristybb503372010-05-27 20:51:26 +00002989static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2990 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002991{
2992 MagickModulo
2993 modulo;
2994
cristy6162bb42011-07-18 11:34:09 +00002995 /*
2996 Compute the remainder of dividing offset by extent. It returns not only
2997 the quotient (tile the offset falls in) but also the positive remainer
2998 within that tile such that 0 <= remainder < extent. This method is
2999 essentially a ldiv() using a floored modulo division rather than the
3000 normal default truncated modulo division.
3001 */
cristybb503372010-05-27 20:51:26 +00003002 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003003 if (offset < 0L)
3004 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003005 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003006 return(modulo);
3007}
3008
cristya6577ff2011-09-02 19:54:26 +00003009MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003010 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3011 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003012 ExceptionInfo *exception)
3013{
3014 CacheInfo
3015 *cache_info;
3016
3017 MagickOffsetType
3018 offset;
3019
3020 MagickSizeType
3021 length,
3022 number_pixels;
3023
3024 NexusInfo
3025 **virtual_nexus;
3026
cristy4c08aed2011-07-01 19:47:50 +00003027 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003028 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003029 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003030
3031 RectangleInfo
3032 region;
3033
cristy4c08aed2011-07-01 19:47:50 +00003034 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003035 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003036
cristy4c08aed2011-07-01 19:47:50 +00003037 register const void
3038 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003039
cristy4c08aed2011-07-01 19:47:50 +00003040 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003041 *restrict q;
3042
cristybb503372010-05-27 20:51:26 +00003043 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003044 i,
3045 u;
cristy3ed852e2009-09-05 21:47:34 +00003046
cristy4c08aed2011-07-01 19:47:50 +00003047 register unsigned char
3048 *restrict s;
3049
cristy105ba3c2011-07-18 02:28:38 +00003050 ssize_t
3051 v;
3052
cristy4c08aed2011-07-01 19:47:50 +00003053 void
cristy105ba3c2011-07-18 02:28:38 +00003054 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003055
cristy3ed852e2009-09-05 21:47:34 +00003056 /*
3057 Acquire pixels.
3058 */
cristye7cc7cf2010-09-21 13:26:47 +00003059 assert(image != (const Image *) NULL);
3060 assert(image->signature == MagickSignature);
3061 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003062 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003063 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003064 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003065 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003066 region.x=x;
3067 region.y=y;
3068 region.width=columns;
3069 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003070 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003071 if (pixels == (Quantum *) NULL)
3072 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003073 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003074 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3075 nexus_info->region.x;
3076 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3077 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003078 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3079 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003080 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3081 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003082 {
3083 MagickBooleanType
3084 status;
3085
3086 /*
3087 Pixel request is inside cache extents.
3088 */
cristy4c08aed2011-07-01 19:47:50 +00003089 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003090 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003091 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3092 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003093 return((const Quantum *) NULL);
3094 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003095 {
cristy4c08aed2011-07-01 19:47:50 +00003096 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003097 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003098 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003099 }
cristyacd2ed22011-08-30 01:44:23 +00003100 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003101 }
3102 /*
3103 Pixel request is outside cache extents.
3104 */
cristy4c08aed2011-07-01 19:47:50 +00003105 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003106 virtual_nexus=AcquirePixelCacheNexus(1);
3107 if (virtual_nexus == (NexusInfo **) NULL)
3108 {
cristy4c08aed2011-07-01 19:47:50 +00003109 if (virtual_nexus != (NexusInfo **) NULL)
3110 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003111 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003112 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003113 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003114 }
cristy105ba3c2011-07-18 02:28:38 +00003115 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3116 sizeof(*virtual_pixel));
3117 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003118 switch (virtual_pixel_method)
3119 {
cristy4c08aed2011-07-01 19:47:50 +00003120 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003121 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003122 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003123 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003124 case MaskVirtualPixelMethod:
3125 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003126 case EdgeVirtualPixelMethod:
3127 case CheckerTileVirtualPixelMethod:
3128 case HorizontalTileVirtualPixelMethod:
3129 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003130 {
cristy4c08aed2011-07-01 19:47:50 +00003131 if (cache_info->metacontent_extent != 0)
3132 {
cristy6162bb42011-07-18 11:34:09 +00003133 /*
3134 Acquire a metacontent buffer.
3135 */
cristya64b85d2011-09-14 01:02:31 +00003136 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003137 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003138 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003139 {
cristy4c08aed2011-07-01 19:47:50 +00003140 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3141 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003142 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003143 return((const Quantum *) NULL);
3144 }
cristy105ba3c2011-07-18 02:28:38 +00003145 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003146 cache_info->metacontent_extent);
3147 }
3148 switch (virtual_pixel_method)
3149 {
3150 case BlackVirtualPixelMethod:
3151 {
cristy30301712011-07-18 15:06:51 +00003152 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3153 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003154 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3155 break;
3156 }
3157 case GrayVirtualPixelMethod:
3158 {
cristy30301712011-07-18 15:06:51 +00003159 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003160 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3161 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003162 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3163 break;
3164 }
3165 case TransparentVirtualPixelMethod:
3166 {
cristy30301712011-07-18 15:06:51 +00003167 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3168 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003169 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3170 break;
3171 }
3172 case MaskVirtualPixelMethod:
3173 case WhiteVirtualPixelMethod:
3174 {
cristy30301712011-07-18 15:06:51 +00003175 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3176 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003177 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3178 break;
3179 }
3180 default:
3181 {
cristy9e0719b2011-12-29 03:45:45 +00003182 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3183 virtual_pixel);
3184 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3185 virtual_pixel);
3186 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3187 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003188 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3189 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003190 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3191 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003192 break;
3193 }
3194 }
cristy3ed852e2009-09-05 21:47:34 +00003195 break;
3196 }
3197 default:
cristy3ed852e2009-09-05 21:47:34 +00003198 break;
cristy3ed852e2009-09-05 21:47:34 +00003199 }
cristybb503372010-05-27 20:51:26 +00003200 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003201 {
cristybb503372010-05-27 20:51:26 +00003202 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003203 {
3204 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003205 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003206 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3207 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003208 {
3209 MagickModulo
3210 x_modulo,
3211 y_modulo;
3212
3213 /*
3214 Transfer a single pixel.
3215 */
3216 length=(MagickSizeType) 1;
3217 switch (virtual_pixel_method)
3218 {
cristy3ed852e2009-09-05 21:47:34 +00003219 default:
3220 {
3221 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003222 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003223 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003224 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003225 break;
3226 }
3227 case RandomVirtualPixelMethod:
3228 {
3229 if (cache_info->random_info == (RandomInfo *) NULL)
3230 cache_info->random_info=AcquireRandomInfo();
3231 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003232 RandomX(cache_info->random_info,cache_info->columns),
3233 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003234 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003235 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003236 break;
3237 }
3238 case DitherVirtualPixelMethod:
3239 {
3240 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003241 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003242 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003243 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003244 break;
3245 }
3246 case TileVirtualPixelMethod:
3247 {
3248 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3249 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3250 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003251 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003252 exception);
cristy4c08aed2011-07-01 19:47:50 +00003253 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003254 break;
3255 }
3256 case MirrorVirtualPixelMethod:
3257 {
3258 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3259 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003260 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003261 x_modulo.remainder-1L;
3262 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3263 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003264 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003265 y_modulo.remainder-1L;
3266 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003267 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003268 exception);
cristy4c08aed2011-07-01 19:47:50 +00003269 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003270 break;
3271 }
3272 case HorizontalTileEdgeVirtualPixelMethod:
3273 {
3274 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3275 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003276 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003277 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003278 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003279 break;
3280 }
3281 case VerticalTileEdgeVirtualPixelMethod:
3282 {
3283 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3284 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003285 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003286 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003287 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3288 break;
3289 }
3290 case BackgroundVirtualPixelMethod:
3291 case BlackVirtualPixelMethod:
3292 case GrayVirtualPixelMethod:
3293 case TransparentVirtualPixelMethod:
3294 case MaskVirtualPixelMethod:
3295 case WhiteVirtualPixelMethod:
3296 {
3297 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003298 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003299 break;
3300 }
3301 case EdgeVirtualPixelMethod:
3302 case CheckerTileVirtualPixelMethod:
3303 {
3304 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3305 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3306 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3307 {
3308 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003309 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003310 break;
3311 }
3312 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3313 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3314 exception);
3315 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3316 break;
3317 }
3318 case HorizontalTileVirtualPixelMethod:
3319 {
3320 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3321 {
3322 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003323 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003324 break;
3325 }
3326 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3327 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3328 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3329 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3330 exception);
3331 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3332 break;
3333 }
3334 case VerticalTileVirtualPixelMethod:
3335 {
3336 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3337 {
3338 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003339 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003340 break;
3341 }
3342 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3343 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3344 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3345 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3346 exception);
3347 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003348 break;
3349 }
3350 }
cristy4c08aed2011-07-01 19:47:50 +00003351 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003352 break;
cristyed231572011-07-14 02:18:59 +00003353 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003354 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003355 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003356 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003357 {
3358 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3359 s+=cache_info->metacontent_extent;
3360 }
cristy3ed852e2009-09-05 21:47:34 +00003361 continue;
3362 }
3363 /*
3364 Transfer a run of pixels.
3365 */
cristy4c08aed2011-07-01 19:47:50 +00003366 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3367 length,1UL,*virtual_nexus,exception);
3368 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003369 break;
cristy4c08aed2011-07-01 19:47:50 +00003370 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003371 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3372 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003373 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003374 {
cristy4c08aed2011-07-01 19:47:50 +00003375 (void) memcpy(s,r,(size_t) length);
3376 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003377 }
3378 }
3379 }
cristy4c08aed2011-07-01 19:47:50 +00003380 /*
3381 Free resources.
3382 */
cristy105ba3c2011-07-18 02:28:38 +00003383 if (virtual_metacontent != (void *) NULL)
3384 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003385 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3386 return(pixels);
3387}
3388
3389/*
3390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3391% %
3392% %
3393% %
3394+ G e t V i r t u a l P i x e l C a c h e %
3395% %
3396% %
3397% %
3398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3399%
3400% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3401% cache as defined by the geometry parameters. A pointer to the pixels
3402% is returned if the pixels are transferred, otherwise a NULL is returned.
3403%
3404% The format of the GetVirtualPixelCache() method is:
3405%
cristy4c08aed2011-07-01 19:47:50 +00003406% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003407% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3408% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003409% ExceptionInfo *exception)
3410%
3411% A description of each parameter follows:
3412%
3413% o image: the image.
3414%
3415% o virtual_pixel_method: the virtual pixel method.
3416%
3417% o x,y,columns,rows: These values define the perimeter of a region of
3418% pixels.
3419%
3420% o exception: return any errors or warnings in this structure.
3421%
3422*/
cristy4c08aed2011-07-01 19:47:50 +00003423static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003424 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3425 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003426{
3427 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003428 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003429
cristy5c9e6f22010-09-17 17:31:01 +00003430 const int
3431 id = GetOpenMPThreadId();
3432
cristy4c08aed2011-07-01 19:47:50 +00003433 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003434 *p;
cristy4c08aed2011-07-01 19:47:50 +00003435
cristye7cc7cf2010-09-21 13:26:47 +00003436 assert(image != (const Image *) NULL);
3437 assert(image->signature == MagickSignature);
3438 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003439 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003440 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003441 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003442 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003443 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003444 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003445}
3446
3447/*
3448%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3449% %
3450% %
3451% %
3452% G e t V i r t u a l P i x e l Q u e u e %
3453% %
3454% %
3455% %
3456%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3457%
cristy4c08aed2011-07-01 19:47:50 +00003458% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3459% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003460%
3461% The format of the GetVirtualPixelQueue() method is:
3462%
cristy4c08aed2011-07-01 19:47:50 +00003463% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003464%
3465% A description of each parameter follows:
3466%
3467% o image: the image.
3468%
3469*/
cristy4c08aed2011-07-01 19:47:50 +00003470MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003471{
3472 CacheInfo
3473 *cache_info;
3474
cristy2036f5c2010-09-19 21:18:17 +00003475 const int
3476 id = GetOpenMPThreadId();
3477
cristy3ed852e2009-09-05 21:47:34 +00003478 assert(image != (const Image *) NULL);
3479 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003480 assert(image->cache != (Cache) NULL);
3481 cache_info=(CacheInfo *) image->cache;
3482 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003483 if (cache_info->methods.get_virtual_pixels_handler !=
3484 (GetVirtualPixelsHandler) NULL)
3485 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003486 assert(id < (int) cache_info->number_threads);
3487 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003488}
3489
3490/*
3491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3492% %
3493% %
3494% %
3495% G e t V i r t u a l P i x e l s %
3496% %
3497% %
3498% %
3499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3500%
3501% GetVirtualPixels() returns an immutable pixel region. If the
3502% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003503% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003504% copy of the pixels or it may point to the original pixels in memory.
3505% Performance is maximized if the selected region is part of one row, or one
3506% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003507% (without a copy) if the image is in memory, or in a memory-mapped file. The
3508% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003509%
3510% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003511% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3512% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3513% access the meta-content (of type void) corresponding to the the
3514% region.
cristy3ed852e2009-09-05 21:47:34 +00003515%
3516% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3517%
3518% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3519% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3520% GetCacheViewAuthenticPixels() instead.
3521%
3522% The format of the GetVirtualPixels() method is:
3523%
cristy4c08aed2011-07-01 19:47:50 +00003524% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003525% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003526% ExceptionInfo *exception)
3527%
3528% A description of each parameter follows:
3529%
3530% o image: the image.
3531%
3532% o x,y,columns,rows: These values define the perimeter of a region of
3533% pixels.
3534%
3535% o exception: return any errors or warnings in this structure.
3536%
3537*/
cristy4c08aed2011-07-01 19:47:50 +00003538MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003539 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3540 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003541{
3542 CacheInfo
3543 *cache_info;
3544
cristy2036f5c2010-09-19 21:18:17 +00003545 const int
3546 id = GetOpenMPThreadId();
3547
cristy4c08aed2011-07-01 19:47:50 +00003548 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003549 *p;
cristy4c08aed2011-07-01 19:47:50 +00003550
cristy3ed852e2009-09-05 21:47:34 +00003551 assert(image != (const Image *) NULL);
3552 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003553 assert(image->cache != (Cache) NULL);
3554 cache_info=(CacheInfo *) image->cache;
3555 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003556 if (cache_info->methods.get_virtual_pixel_handler !=
3557 (GetVirtualPixelHandler) NULL)
3558 return(cache_info->methods.get_virtual_pixel_handler(image,
3559 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003560 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003561 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003562 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003563 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003564}
3565
3566/*
3567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3568% %
3569% %
3570% %
3571+ 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 %
3572% %
3573% %
3574% %
3575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3576%
cristy4c08aed2011-07-01 19:47:50 +00003577% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3578% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003579%
3580% The format of the GetVirtualPixelsCache() method is:
3581%
cristy4c08aed2011-07-01 19:47:50 +00003582% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003583%
3584% A description of each parameter follows:
3585%
3586% o image: the image.
3587%
3588*/
cristy4c08aed2011-07-01 19:47:50 +00003589static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003590{
3591 CacheInfo
3592 *cache_info;
3593
cristy5c9e6f22010-09-17 17:31:01 +00003594 const int
3595 id = GetOpenMPThreadId();
3596
cristye7cc7cf2010-09-21 13:26:47 +00003597 assert(image != (const Image *) NULL);
3598 assert(image->signature == MagickSignature);
3599 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003600 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003601 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003602 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003603 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003604}
3605
3606/*
3607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3608% %
3609% %
3610% %
3611+ G e t V i r t u a l P i x e l s N e x u s %
3612% %
3613% %
3614% %
3615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3616%
3617% GetVirtualPixelsNexus() returns the pixels associated with the specified
3618% cache nexus.
3619%
3620% The format of the GetVirtualPixelsNexus() method is:
3621%
cristy4c08aed2011-07-01 19:47:50 +00003622% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003623% NexusInfo *nexus_info)
3624%
3625% A description of each parameter follows:
3626%
3627% o cache: the pixel cache.
3628%
3629% o nexus_info: the cache nexus to return the colormap pixels.
3630%
3631*/
cristya6577ff2011-09-02 19:54:26 +00003632MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003633 NexusInfo *nexus_info)
3634{
3635 CacheInfo
3636 *cache_info;
3637
cristye7cc7cf2010-09-21 13:26:47 +00003638 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003639 cache_info=(CacheInfo *) cache;
3640 assert(cache_info->signature == MagickSignature);
3641 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003642 return((Quantum *) NULL);
3643 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003644}
3645
3646/*
3647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3648% %
3649% %
3650% %
cristy3ed852e2009-09-05 21:47:34 +00003651+ O p e n P i x e l C a c h e %
3652% %
3653% %
3654% %
3655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3656%
3657% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3658% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003659% metacontent, and memory mapping the cache if it is disk based. The cache
3660% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003661%
3662% The format of the OpenPixelCache() method is:
3663%
3664% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3665% ExceptionInfo *exception)
3666%
3667% A description of each parameter follows:
3668%
3669% o image: the image.
3670%
3671% o mode: ReadMode, WriteMode, or IOMode.
3672%
3673% o exception: return any errors or warnings in this structure.
3674%
3675*/
3676
cristyd43a46b2010-01-21 02:13:41 +00003677static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003678{
3679 cache_info->mapped=MagickFalse;
cristy9dd0b6f2012-08-01 14:38:43 +00003680 cache_info->pixels=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003681 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003682 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003683 {
3684 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003685 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003686 cache_info->length);
3687 }
3688}
3689
3690static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3691{
3692 CacheInfo
3693 *cache_info;
3694
3695 MagickOffsetType
3696 count,
3697 extent,
3698 offset;
3699
3700 cache_info=(CacheInfo *) image->cache;
3701 if (image->debug != MagickFalse)
3702 {
3703 char
3704 format[MaxTextExtent],
3705 message[MaxTextExtent];
3706
cristyb9080c92009-12-01 20:13:26 +00003707 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003708 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003709 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003710 cache_info->cache_filename,cache_info->file,format);
3711 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3712 }
3713 if (length != (MagickSizeType) ((MagickOffsetType) length))
3714 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003715 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003716 if (extent < 0)
3717 return(MagickFalse);
3718 if ((MagickSizeType) extent >= length)
3719 return(MagickTrue);
3720 offset=(MagickOffsetType) length-1;
3721 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3722 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3723}
3724
3725static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3726 ExceptionInfo *exception)
3727{
cristy3ed852e2009-09-05 21:47:34 +00003728 CacheInfo
3729 *cache_info,
3730 source_info;
3731
cristyf3a6a9d2010-11-07 21:02:56 +00003732 char
3733 format[MaxTextExtent],
3734 message[MaxTextExtent];
3735
cristy4c08aed2011-07-01 19:47:50 +00003736 MagickBooleanType
3737 status;
3738
cristy3ed852e2009-09-05 21:47:34 +00003739 MagickSizeType
3740 length,
3741 number_pixels;
3742
cristy3ed852e2009-09-05 21:47:34 +00003743 size_t
cristye076a6e2010-08-15 19:59:43 +00003744 columns,
cristy3ed852e2009-09-05 21:47:34 +00003745 packet_size;
3746
cristye7cc7cf2010-09-21 13:26:47 +00003747 assert(image != (const Image *) NULL);
3748 assert(image->signature == MagickSignature);
3749 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003750 if (image->debug != MagickFalse)
3751 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3752 if ((image->columns == 0) || (image->rows == 0))
3753 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3754 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003755 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003756 source_info=(*cache_info);
3757 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003758 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003759 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003760 cache_info->storage_class=image->storage_class;
3761 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003762 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003763 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003764 cache_info->rows=image->rows;
3765 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003766 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003767 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003768 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3769 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003770 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003771 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003772 if (image->ping != MagickFalse)
3773 {
cristy73724512010-04-12 14:43:14 +00003774 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003775 cache_info->pixels=(Quantum *) NULL;
3776 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003777 cache_info->length=0;
3778 return(MagickTrue);
3779 }
cristy3ed852e2009-09-05 21:47:34 +00003780 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003781 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003782 if (image->metacontent_extent != 0)
3783 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003784 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003785 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003786 if (cache_info->columns != columns)
3787 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3788 image->filename);
3789 cache_info->length=length;
3790 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003791 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003792 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003793 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3794 {
3795 status=AcquireMagickResource(MemoryResource,cache_info->length);
3796 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3797 (cache_info->type == MemoryCache))
3798 {
cristyd43a46b2010-01-21 02:13:41 +00003799 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003800 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003801 cache_info->pixels=source_info.pixels;
3802 else
3803 {
3804 /*
3805 Create memory pixel cache.
3806 */
cristy4c08aed2011-07-01 19:47:50 +00003807 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003808 if (image->debug != MagickFalse)
3809 {
cristy32cacff2011-12-31 03:36:27 +00003810 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003811 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003812 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3813 cache_info->filename,cache_info->mapped != MagickFalse ?
3814 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003815 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003816 format);
cristy3ed852e2009-09-05 21:47:34 +00003817 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3818 message);
3819 }
cristy3ed852e2009-09-05 21:47:34 +00003820 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003821 cache_info->metacontent=(void *) NULL;
3822 if (cache_info->metacontent_extent != 0)
3823 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003824 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003825 if ((source_info.storage_class != UndefinedClass) &&
3826 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003827 {
cristy4c08aed2011-07-01 19:47:50 +00003828 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003829 exception);
3830 RelinquishPixelCachePixels(&source_info);
3831 }
cristy4c08aed2011-07-01 19:47:50 +00003832 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003833 }
3834 }
3835 RelinquishMagickResource(MemoryResource,cache_info->length);
3836 }
3837 /*
3838 Create pixel cache on disk.
3839 */
3840 status=AcquireMagickResource(DiskResource,cache_info->length);
3841 if (status == MagickFalse)
3842 {
3843 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003844 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003845 return(MagickFalse);
3846 }
cristy413f1302012-01-01 17:48:27 +00003847 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3848 {
3849 (void) ClosePixelCacheOnDisk(cache_info);
3850 *cache_info->cache_filename='\0';
3851 }
cristy3ed852e2009-09-05 21:47:34 +00003852 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3853 {
3854 RelinquishMagickResource(DiskResource,cache_info->length);
3855 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3856 image->filename);
3857 return(MagickFalse);
3858 }
3859 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3860 cache_info->length);
3861 if (status == MagickFalse)
3862 {
3863 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3864 image->filename);
3865 return(MagickFalse);
3866 }
cristyed231572011-07-14 02:18:59 +00003867 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003868 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003869 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003870 cache_info->type=DiskCache;
3871 else
3872 {
3873 status=AcquireMagickResource(MapResource,cache_info->length);
3874 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3875 (cache_info->type != MemoryCache))
3876 cache_info->type=DiskCache;
3877 else
3878 {
cristy4c08aed2011-07-01 19:47:50 +00003879 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003880 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003881 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003882 {
cristy3ed852e2009-09-05 21:47:34 +00003883 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003884 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003885 }
3886 else
3887 {
3888 /*
3889 Create file-backed memory-mapped pixel cache.
3890 */
cristy4c08aed2011-07-01 19:47:50 +00003891 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003892 (void) ClosePixelCacheOnDisk(cache_info);
3893 cache_info->type=MapCache;
3894 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003895 cache_info->metacontent=(void *) NULL;
3896 if (cache_info->metacontent_extent != 0)
3897 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003898 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003899 if ((source_info.storage_class != UndefinedClass) &&
3900 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003901 {
3902 status=ClonePixelCachePixels(cache_info,&source_info,
3903 exception);
3904 RelinquishPixelCachePixels(&source_info);
3905 }
3906 if (image->debug != MagickFalse)
3907 {
cristy413f1302012-01-01 17:48:27 +00003908 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003909 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003910 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003911 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003912 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003913 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003914 format);
cristy3ed852e2009-09-05 21:47:34 +00003915 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3916 message);
3917 }
cristy4c08aed2011-07-01 19:47:50 +00003918 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003919 }
3920 }
3921 RelinquishMagickResource(MapResource,cache_info->length);
3922 }
cristy4c08aed2011-07-01 19:47:50 +00003923 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003924 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003925 {
3926 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3927 RelinquishPixelCachePixels(&source_info);
3928 }
3929 if (image->debug != MagickFalse)
3930 {
cristyb9080c92009-12-01 20:13:26 +00003931 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003932 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003933 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003934 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003935 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003936 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003937 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3938 }
cristy4c08aed2011-07-01 19:47:50 +00003939 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003940}
3941
3942/*
3943%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3944% %
3945% %
3946% %
3947+ P e r s i s t P i x e l C a c h e %
3948% %
3949% %
3950% %
3951%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3952%
3953% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3954% persistent pixel cache is one that resides on disk and is not destroyed
3955% when the program exits.
3956%
3957% The format of the PersistPixelCache() method is:
3958%
3959% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3960% const MagickBooleanType attach,MagickOffsetType *offset,
3961% ExceptionInfo *exception)
3962%
3963% A description of each parameter follows:
3964%
3965% o image: the image.
3966%
3967% o filename: the persistent pixel cache filename.
3968%
cristyf3a6a9d2010-11-07 21:02:56 +00003969% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003970%
cristy3ed852e2009-09-05 21:47:34 +00003971% o initialize: A value other than zero initializes the persistent pixel
3972% cache.
3973%
3974% o offset: the offset in the persistent cache to store pixels.
3975%
3976% o exception: return any errors or warnings in this structure.
3977%
3978*/
3979MagickExport MagickBooleanType PersistPixelCache(Image *image,
3980 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3981 ExceptionInfo *exception)
3982{
3983 CacheInfo
3984 *cache_info,
3985 *clone_info;
3986
3987 Image
3988 clone_image;
3989
cristy3ed852e2009-09-05 21:47:34 +00003990 MagickBooleanType
3991 status;
3992
cristye076a6e2010-08-15 19:59:43 +00003993 ssize_t
3994 page_size;
3995
cristy3ed852e2009-09-05 21:47:34 +00003996 assert(image != (Image *) NULL);
3997 assert(image->signature == MagickSignature);
3998 if (image->debug != MagickFalse)
3999 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4000 assert(image->cache != (void *) NULL);
4001 assert(filename != (const char *) NULL);
4002 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004003 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004004 cache_info=(CacheInfo *) image->cache;
4005 assert(cache_info->signature == MagickSignature);
4006 if (attach != MagickFalse)
4007 {
4008 /*
cristy01b7eb02009-09-10 23:10:14 +00004009 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004010 */
4011 if (image->debug != MagickFalse)
4012 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004013 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004014 (void) CopyMagickString(cache_info->cache_filename,filename,
4015 MaxTextExtent);
4016 cache_info->type=DiskCache;
4017 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004018 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004019 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004020 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004021 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004022 }
cristy01b7eb02009-09-10 23:10:14 +00004023 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4024 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004025 {
cristyf84a1932010-01-03 18:00:18 +00004026 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004027 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004028 (cache_info->reference_count == 1))
4029 {
4030 int
4031 status;
4032
4033 /*
cristy01b7eb02009-09-10 23:10:14 +00004034 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004035 */
cristy320684d2011-09-23 14:55:47 +00004036 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004037 if (status == 0)
4038 {
4039 (void) CopyMagickString(cache_info->cache_filename,filename,
4040 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004041 *offset+=cache_info->length+page_size-(cache_info->length %
4042 page_size);
cristyf84a1932010-01-03 18:00:18 +00004043 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004044 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004045 if (image->debug != MagickFalse)
4046 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4047 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004048 return(MagickTrue);
4049 }
4050 }
cristyf84a1932010-01-03 18:00:18 +00004051 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004052 }
4053 /*
cristy01b7eb02009-09-10 23:10:14 +00004054 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004055 */
4056 clone_image=(*image);
4057 clone_info=(CacheInfo *) clone_image.cache;
4058 image->cache=ClonePixelCache(cache_info);
4059 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4060 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4061 cache_info->type=DiskCache;
4062 cache_info->offset=(*offset);
4063 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004064 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004065 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004066 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004067 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004068 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4069 return(status);
4070}
4071
4072/*
4073%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4074% %
4075% %
4076% %
cristyc11dace2012-01-24 16:39:46 +00004077+ 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 +00004078% %
4079% %
4080% %
4081%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4082%
cristyc11dace2012-01-24 16:39:46 +00004083% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4084% defined by the region rectangle and returns a pointer to the region. This
4085% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004086% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4087% pixels are transferred, otherwise a NULL is returned.
4088%
cristyc11dace2012-01-24 16:39:46 +00004089% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004090%
cristyc11dace2012-01-24 16:39:46 +00004091% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004092% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004093% const MagickBooleanType clone,NexusInfo *nexus_info,
4094% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004095%
4096% A description of each parameter follows:
4097%
4098% o image: the image.
4099%
4100% o x,y,columns,rows: These values define the perimeter of a region of
4101% pixels.
4102%
4103% o nexus_info: the cache nexus to set.
4104%
cristy65dbf172011-10-06 17:32:04 +00004105% o clone: clone the pixel cache.
4106%
cristy3ed852e2009-09-05 21:47:34 +00004107% o exception: return any errors or warnings in this structure.
4108%
4109*/
cristyc11dace2012-01-24 16:39:46 +00004110MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4111 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004112 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004113{
4114 CacheInfo
4115 *cache_info;
4116
4117 MagickOffsetType
4118 offset;
4119
4120 MagickSizeType
4121 number_pixels;
4122
4123 RectangleInfo
4124 region;
4125
4126 /*
4127 Validate pixel cache geometry.
4128 */
cristye7cc7cf2010-09-21 13:26:47 +00004129 assert(image != (const Image *) NULL);
4130 assert(image->signature == MagickSignature);
4131 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004132 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004133 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004134 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004135 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004136 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4137 {
4138 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004139 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004140 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004141 }
cristybb503372010-05-27 20:51:26 +00004142 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4143 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004144 {
4145 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004146 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004147 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004148 }
4149 offset=(MagickOffsetType) y*cache_info->columns+x;
4150 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004151 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004152 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4153 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4154 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004155 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004156 /*
4157 Return pixel cache.
4158 */
4159 region.x=x;
4160 region.y=y;
4161 region.width=columns;
4162 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004163 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004164}
4165
4166/*
4167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4168% %
4169% %
4170% %
4171+ 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 %
4172% %
4173% %
4174% %
4175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4176%
4177% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4178% defined by the region rectangle and returns a pointer to the region. This
4179% region is subsequently transferred from the pixel cache with
4180% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4181% pixels are transferred, otherwise a NULL is returned.
4182%
4183% The format of the QueueAuthenticPixelsCache() method is:
4184%
cristy4c08aed2011-07-01 19:47:50 +00004185% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004186% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004187% ExceptionInfo *exception)
4188%
4189% A description of each parameter follows:
4190%
4191% o image: the image.
4192%
4193% o x,y,columns,rows: These values define the perimeter of a region of
4194% pixels.
4195%
4196% o exception: return any errors or warnings in this structure.
4197%
4198*/
cristy4c08aed2011-07-01 19:47:50 +00004199static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004200 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004201 ExceptionInfo *exception)
4202{
4203 CacheInfo
4204 *cache_info;
4205
cristy5c9e6f22010-09-17 17:31:01 +00004206 const int
4207 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004208
cristy4c08aed2011-07-01 19:47:50 +00004209 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004210 *q;
cristy4c08aed2011-07-01 19:47:50 +00004211
cristye7cc7cf2010-09-21 13:26:47 +00004212 assert(image != (const Image *) NULL);
4213 assert(image->signature == MagickSignature);
4214 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004215 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004216 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004217 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004218 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004219 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004220 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004221}
4222
4223/*
4224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4225% %
4226% %
4227% %
4228% Q u e u e A u t h e n t i c P i x e l s %
4229% %
4230% %
4231% %
4232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4233%
4234% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004235% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004236% region is returned, otherwise NULL is returned. The returned pointer may
4237% point to a temporary working buffer for the pixels or it may point to the
4238% final location of the pixels in memory.
4239%
4240% Write-only access means that any existing pixel values corresponding to
4241% the region are ignored. This is useful if the initial image is being
4242% created from scratch, or if the existing pixel values are to be
4243% completely replaced without need to refer to their pre-existing values.
4244% The application is free to read and write the pixel buffer returned by
4245% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4246% initialize the pixel array values. Initializing pixel array values is the
4247% application's responsibility.
4248%
4249% Performance is maximized if the selected region is part of one row, or
4250% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004251% pixels in-place (without a copy) if the image is in memory, or in a
4252% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004253% by the user.
4254%
4255% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004256% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4257% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4258% obtain the meta-content (of type void) corresponding to the region.
4259% Once the Quantum (and/or Quantum) array has been updated, the
4260% changes must be saved back to the underlying image using
4261% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004262%
4263% The format of the QueueAuthenticPixels() method is:
4264%
cristy4c08aed2011-07-01 19:47:50 +00004265% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004266% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004267% ExceptionInfo *exception)
4268%
4269% A description of each parameter follows:
4270%
4271% o image: the image.
4272%
4273% o x,y,columns,rows: These values define the perimeter of a region of
4274% pixels.
4275%
4276% o exception: return any errors or warnings in this structure.
4277%
4278*/
cristy4c08aed2011-07-01 19:47:50 +00004279MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004280 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004281 ExceptionInfo *exception)
4282{
4283 CacheInfo
4284 *cache_info;
4285
cristy2036f5c2010-09-19 21:18:17 +00004286 const int
4287 id = GetOpenMPThreadId();
4288
cristy4c08aed2011-07-01 19:47:50 +00004289 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004290 *q;
cristy4c08aed2011-07-01 19:47:50 +00004291
cristy3ed852e2009-09-05 21:47:34 +00004292 assert(image != (Image *) NULL);
4293 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004294 assert(image->cache != (Cache) NULL);
4295 cache_info=(CacheInfo *) image->cache;
4296 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004297 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004298 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004299 {
cristyc36c8822012-02-14 14:02:36 +00004300 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4301 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004302 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004303 }
cristy2036f5c2010-09-19 21:18:17 +00004304 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004305 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004306 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004307 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004308}
4309
4310/*
4311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4312% %
4313% %
4314% %
cristy4c08aed2011-07-01 19:47:50 +00004315+ 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 +00004316% %
4317% %
4318% %
4319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4320%
cristy4c08aed2011-07-01 19:47:50 +00004321% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004322% the pixel cache.
4323%
cristy4c08aed2011-07-01 19:47:50 +00004324% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004325%
cristy4c08aed2011-07-01 19:47:50 +00004326% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004327% NexusInfo *nexus_info,ExceptionInfo *exception)
4328%
4329% A description of each parameter follows:
4330%
4331% o cache_info: the pixel cache.
4332%
cristy4c08aed2011-07-01 19:47:50 +00004333% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004334%
4335% o exception: return any errors or warnings in this structure.
4336%
4337*/
cristy4c08aed2011-07-01 19:47:50 +00004338static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004339 NexusInfo *nexus_info,ExceptionInfo *exception)
4340{
4341 MagickOffsetType
4342 count,
4343 offset;
4344
4345 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004346 extent,
4347 length;
cristy3ed852e2009-09-05 21:47:34 +00004348
cristybb503372010-05-27 20:51:26 +00004349 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004350 y;
4351
cristy4c08aed2011-07-01 19:47:50 +00004352 register unsigned char
4353 *restrict q;
4354
cristybb503372010-05-27 20:51:26 +00004355 size_t
cristy3ed852e2009-09-05 21:47:34 +00004356 rows;
4357
cristy4c08aed2011-07-01 19:47:50 +00004358 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004359 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004360 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004361 return(MagickTrue);
4362 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4363 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004364 length=(MagickSizeType) nexus_info->region.width*
4365 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004366 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004367 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004368 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004369 switch (cache_info->type)
4370 {
4371 case MemoryCache:
4372 case MapCache:
4373 {
cristy4c08aed2011-07-01 19:47:50 +00004374 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004375 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004376
4377 /*
cristy4c08aed2011-07-01 19:47:50 +00004378 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004379 */
cristydd341db2010-03-04 19:06:38 +00004380 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004381 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004382 {
cristy48078b12010-09-23 17:11:01 +00004383 length=extent;
cristydd341db2010-03-04 19:06:38 +00004384 rows=1UL;
4385 }
cristy4c08aed2011-07-01 19:47:50 +00004386 p=(unsigned char *) cache_info->metacontent+offset*
4387 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004388 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004389 {
cristy8f036fe2010-09-18 02:02:00 +00004390 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004391 p+=cache_info->metacontent_extent*cache_info->columns;
4392 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004393 }
4394 break;
4395 }
4396 case DiskCache:
4397 {
4398 /*
cristy4c08aed2011-07-01 19:47:50 +00004399 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004400 */
4401 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4402 {
4403 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4404 cache_info->cache_filename);
4405 return(MagickFalse);
4406 }
cristydd341db2010-03-04 19:06:38 +00004407 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004408 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004409 {
cristy48078b12010-09-23 17:11:01 +00004410 length=extent;
cristydd341db2010-03-04 19:06:38 +00004411 rows=1UL;
4412 }
cristy48078b12010-09-23 17:11:01 +00004413 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004414 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004415 {
cristy48078b12010-09-23 17:11:01 +00004416 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004417 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004418 cache_info->metacontent_extent,length,(unsigned char *) q);
4419 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004420 break;
4421 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004422 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004423 }
cristyc11dace2012-01-24 16:39:46 +00004424 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4425 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004426 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004427 {
4428 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4429 cache_info->cache_filename);
4430 return(MagickFalse);
4431 }
4432 break;
4433 }
4434 default:
4435 break;
4436 }
4437 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004438 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004439 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004440 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004441 nexus_info->region.width,(double) nexus_info->region.height,(double)
4442 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004443 return(MagickTrue);
4444}
4445
4446/*
4447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4448% %
4449% %
4450% %
4451+ R e a d P i x e l C a c h e P i x e l s %
4452% %
4453% %
4454% %
4455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4456%
4457% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4458% cache.
4459%
4460% The format of the ReadPixelCachePixels() method is:
4461%
4462% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4463% NexusInfo *nexus_info,ExceptionInfo *exception)
4464%
4465% A description of each parameter follows:
4466%
4467% o cache_info: the pixel cache.
4468%
4469% o nexus_info: the cache nexus to read the pixels.
4470%
4471% o exception: return any errors or warnings in this structure.
4472%
4473*/
4474static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4475 NexusInfo *nexus_info,ExceptionInfo *exception)
4476{
4477 MagickOffsetType
4478 count,
4479 offset;
4480
4481 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004482 extent,
4483 length;
cristy3ed852e2009-09-05 21:47:34 +00004484
cristy4c08aed2011-07-01 19:47:50 +00004485 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004486 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004487
cristye076a6e2010-08-15 19:59:43 +00004488 register ssize_t
4489 y;
4490
cristybb503372010-05-27 20:51:26 +00004491 size_t
cristy3ed852e2009-09-05 21:47:34 +00004492 rows;
4493
cristy4c08aed2011-07-01 19:47:50 +00004494 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004495 return(MagickTrue);
4496 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4497 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004498 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004499 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004500 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004501 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004502 q=nexus_info->pixels;
4503 switch (cache_info->type)
4504 {
4505 case MemoryCache:
4506 case MapCache:
4507 {
cristy4c08aed2011-07-01 19:47:50 +00004508 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004509 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004510
4511 /*
4512 Read pixels from memory.
4513 */
cristydd341db2010-03-04 19:06:38 +00004514 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004515 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004516 {
cristy48078b12010-09-23 17:11:01 +00004517 length=extent;
cristydd341db2010-03-04 19:06:38 +00004518 rows=1UL;
4519 }
cristyed231572011-07-14 02:18:59 +00004520 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004521 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004522 {
cristy8f036fe2010-09-18 02:02:00 +00004523 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004524 p+=cache_info->number_channels*cache_info->columns;
4525 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004526 }
4527 break;
4528 }
4529 case DiskCache:
4530 {
4531 /*
4532 Read pixels from disk.
4533 */
4534 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4535 {
4536 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4537 cache_info->cache_filename);
4538 return(MagickFalse);
4539 }
cristydd341db2010-03-04 19:06:38 +00004540 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004541 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004542 {
cristy48078b12010-09-23 17:11:01 +00004543 length=extent;
cristydd341db2010-03-04 19:06:38 +00004544 rows=1UL;
4545 }
cristybb503372010-05-27 20:51:26 +00004546 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004547 {
4548 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004549 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004550 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004551 break;
4552 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004553 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004554 }
cristyc11dace2012-01-24 16:39:46 +00004555 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4556 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004557 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004558 {
4559 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4560 cache_info->cache_filename);
4561 return(MagickFalse);
4562 }
4563 break;
4564 }
4565 default:
4566 break;
4567 }
4568 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004569 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004570 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004571 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004572 nexus_info->region.width,(double) nexus_info->region.height,(double)
4573 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004574 return(MagickTrue);
4575}
4576
4577/*
4578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4579% %
4580% %
4581% %
4582+ R e f e r e n c e P i x e l C a c h e %
4583% %
4584% %
4585% %
4586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4587%
4588% ReferencePixelCache() increments the reference count associated with the
4589% pixel cache returning a pointer to the cache.
4590%
4591% The format of the ReferencePixelCache method is:
4592%
4593% Cache ReferencePixelCache(Cache cache_info)
4594%
4595% A description of each parameter follows:
4596%
4597% o cache_info: the pixel cache.
4598%
4599*/
cristya6577ff2011-09-02 19:54:26 +00004600MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004601{
4602 CacheInfo
4603 *cache_info;
4604
4605 assert(cache != (Cache *) NULL);
4606 cache_info=(CacheInfo *) cache;
4607 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004608 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004609 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004610 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004611 return(cache_info);
4612}
4613
4614/*
4615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4616% %
4617% %
4618% %
4619+ S e t P i x e l C a c h e M e t h o d s %
4620% %
4621% %
4622% %
4623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4624%
4625% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4626%
4627% The format of the SetPixelCacheMethods() method is:
4628%
4629% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4630%
4631% A description of each parameter follows:
4632%
4633% o cache: the pixel cache.
4634%
4635% o cache_methods: Specifies a pointer to a CacheMethods structure.
4636%
4637*/
cristya6577ff2011-09-02 19:54:26 +00004638MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004639{
4640 CacheInfo
4641 *cache_info;
4642
4643 GetOneAuthenticPixelFromHandler
4644 get_one_authentic_pixel_from_handler;
4645
4646 GetOneVirtualPixelFromHandler
4647 get_one_virtual_pixel_from_handler;
4648
4649 /*
4650 Set cache pixel methods.
4651 */
4652 assert(cache != (Cache) NULL);
4653 assert(cache_methods != (CacheMethods *) NULL);
4654 cache_info=(CacheInfo *) cache;
4655 assert(cache_info->signature == MagickSignature);
4656 if (cache_info->debug != MagickFalse)
4657 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4658 cache_info->filename);
4659 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4660 cache_info->methods.get_virtual_pixel_handler=
4661 cache_methods->get_virtual_pixel_handler;
4662 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4663 cache_info->methods.destroy_pixel_handler=
4664 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004665 if (cache_methods->get_virtual_metacontent_from_handler !=
4666 (GetVirtualMetacontentFromHandler) NULL)
4667 cache_info->methods.get_virtual_metacontent_from_handler=
4668 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004669 if (cache_methods->get_authentic_pixels_handler !=
4670 (GetAuthenticPixelsHandler) NULL)
4671 cache_info->methods.get_authentic_pixels_handler=
4672 cache_methods->get_authentic_pixels_handler;
4673 if (cache_methods->queue_authentic_pixels_handler !=
4674 (QueueAuthenticPixelsHandler) NULL)
4675 cache_info->methods.queue_authentic_pixels_handler=
4676 cache_methods->queue_authentic_pixels_handler;
4677 if (cache_methods->sync_authentic_pixels_handler !=
4678 (SyncAuthenticPixelsHandler) NULL)
4679 cache_info->methods.sync_authentic_pixels_handler=
4680 cache_methods->sync_authentic_pixels_handler;
4681 if (cache_methods->get_authentic_pixels_from_handler !=
4682 (GetAuthenticPixelsFromHandler) NULL)
4683 cache_info->methods.get_authentic_pixels_from_handler=
4684 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004685 if (cache_methods->get_authentic_metacontent_from_handler !=
4686 (GetAuthenticMetacontentFromHandler) NULL)
4687 cache_info->methods.get_authentic_metacontent_from_handler=
4688 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004689 get_one_virtual_pixel_from_handler=
4690 cache_info->methods.get_one_virtual_pixel_from_handler;
4691 if (get_one_virtual_pixel_from_handler !=
4692 (GetOneVirtualPixelFromHandler) NULL)
4693 cache_info->methods.get_one_virtual_pixel_from_handler=
4694 cache_methods->get_one_virtual_pixel_from_handler;
4695 get_one_authentic_pixel_from_handler=
4696 cache_methods->get_one_authentic_pixel_from_handler;
4697 if (get_one_authentic_pixel_from_handler !=
4698 (GetOneAuthenticPixelFromHandler) NULL)
4699 cache_info->methods.get_one_authentic_pixel_from_handler=
4700 cache_methods->get_one_authentic_pixel_from_handler;
4701}
4702
4703/*
4704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4705% %
4706% %
4707% %
4708+ S e t P i x e l C a c h e N e x u s P i x e l s %
4709% %
4710% %
4711% %
4712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4713%
4714% SetPixelCacheNexusPixels() defines the region of the cache for the
4715% specified cache nexus.
4716%
4717% The format of the SetPixelCacheNexusPixels() method is:
4718%
cristy265a2b22012-05-11 12:48:50 +00004719% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004720% const RectangleInfo *region,NexusInfo *nexus_info,
4721% ExceptionInfo *exception)
4722%
4723% A description of each parameter follows:
4724%
4725% o image: the image.
4726%
cristy265a2b22012-05-11 12:48:50 +00004727% o mode: ReadMode, WriteMode, or IOMode.
4728%
cristy3ed852e2009-09-05 21:47:34 +00004729% o region: A pointer to the RectangleInfo structure that defines the
4730% region of this particular cache nexus.
4731%
4732% o nexus_info: the cache nexus to set.
4733%
4734% o exception: return any errors or warnings in this structure.
4735%
4736*/
cristyabd6e372010-09-15 19:11:26 +00004737
cristyf1832792012-05-08 18:38:18 +00004738static inline MagickBooleanType AcquireCacheNexusPixels(
4739 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4740 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004741{
4742 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4743 return(MagickFalse);
4744 nexus_info->mapped=MagickFalse;
cristy9dd0b6f2012-08-01 14:38:43 +00004745 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004746 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004747 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004748 {
4749 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004750 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004751 nexus_info->length);
4752 }
cristy4c08aed2011-07-01 19:47:50 +00004753 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004754 {
4755 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004756 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004757 cache_info->filename);
4758 return(MagickFalse);
4759 }
4760 return(MagickTrue);
4761}
4762
cristyadf82722012-05-11 17:34:16 +00004763static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4764 const MapMode mode)
4765{
cristyfc5845e2012-05-11 18:18:13 +00004766 if (mode == ReadMode)
4767 {
4768 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4769 return;
4770 }
4771 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004772}
4773
cristy265a2b22012-05-11 12:48:50 +00004774static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004775 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4776{
4777 CacheInfo
4778 *cache_info;
4779
4780 MagickBooleanType
4781 status;
4782
cristy3ed852e2009-09-05 21:47:34 +00004783 MagickSizeType
4784 length,
4785 number_pixels;
4786
cristy3ed852e2009-09-05 21:47:34 +00004787 cache_info=(CacheInfo *) image->cache;
4788 assert(cache_info->signature == MagickSignature);
4789 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004790 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004791 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004792 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004793 {
cristybb503372010-05-27 20:51:26 +00004794 ssize_t
cristybad067a2010-02-15 17:20:55 +00004795 x,
4796 y;
cristy3ed852e2009-09-05 21:47:34 +00004797
cristyeaedf062010-05-29 22:36:02 +00004798 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4799 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004800 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4801 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004802 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004803 ((nexus_info->region.width == cache_info->columns) ||
4804 ((nexus_info->region.width % cache_info->columns) == 0)))))
4805 {
4806 MagickOffsetType
4807 offset;
4808
4809 /*
4810 Pixels are accessed directly from memory.
4811 */
4812 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4813 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004814 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004815 offset;
4816 nexus_info->metacontent=(void *) NULL;
4817 if (cache_info->metacontent_extent != 0)
4818 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4819 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004820 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004821 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004822 }
4823 }
4824 /*
4825 Pixels are stored in a cache region until they are synced to the cache.
4826 */
4827 number_pixels=(MagickSizeType) nexus_info->region.width*
4828 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004829 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004830 if (cache_info->metacontent_extent != 0)
4831 length+=number_pixels*cache_info->metacontent_extent;
4832 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004833 {
4834 nexus_info->length=length;
4835 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4836 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004837 {
4838 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004839 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004840 }
cristy3ed852e2009-09-05 21:47:34 +00004841 }
4842 else
4843 if (nexus_info->length != length)
4844 {
4845 RelinquishCacheNexusPixels(nexus_info);
4846 nexus_info->length=length;
4847 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4848 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004849 {
4850 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004851 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004852 }
cristy3ed852e2009-09-05 21:47:34 +00004853 }
4854 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004855 nexus_info->metacontent=(void *) NULL;
4856 if (cache_info->metacontent_extent != 0)
4857 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004858 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004859 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004860 return(nexus_info->pixels);
4861}
4862
4863/*
4864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4865% %
4866% %
4867% %
4868% 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 %
4869% %
4870% %
4871% %
4872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4873%
4874% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4875% pixel cache and returns the previous setting. A virtual pixel is any pixel
4876% access that is outside the boundaries of the image cache.
4877%
4878% The format of the SetPixelCacheVirtualMethod() method is:
4879%
cristy387430f2012-02-07 13:09:46 +00004880% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4881% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004882%
4883% A description of each parameter follows:
4884%
4885% o image: the image.
4886%
4887% o virtual_pixel_method: choose the type of virtual pixel.
4888%
cristy387430f2012-02-07 13:09:46 +00004889% o exception: return any errors or warnings in this structure.
4890%
cristy3ed852e2009-09-05 21:47:34 +00004891*/
cristy3d4cb882012-02-07 19:11:26 +00004892
4893static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4894 ExceptionInfo *exception)
4895{
4896 CacheInfo
4897 *cache_info;
4898
cristyf2719112012-05-06 18:38:46 +00004899 CacheView
4900 *image_view;
4901
cristy3d4cb882012-02-07 19:11:26 +00004902 MagickBooleanType
4903 status;
4904
4905 ssize_t
4906 y;
4907
4908 assert(image != (Image *) NULL);
4909 assert(image->signature == MagickSignature);
4910 if (image->debug != MagickFalse)
4911 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4912 assert(image->cache != (Cache) NULL);
4913 cache_info=(CacheInfo *) image->cache;
4914 assert(cache_info->signature == MagickSignature);
4915 image->matte=MagickTrue;
4916 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004917 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004918#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00004919 #pragma omp parallel for schedule(static) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00004920 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004921#endif
4922 for (y=0; y < (ssize_t) image->rows; y++)
4923 {
cristy3d4cb882012-02-07 19:11:26 +00004924 register Quantum
4925 *restrict q;
4926
4927 register ssize_t
4928 x;
4929
4930 if (status == MagickFalse)
4931 continue;
cristy23d198a2012-03-13 13:48:08 +00004932 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004933 if (q == (Quantum *) NULL)
4934 {
4935 status=MagickFalse;
4936 continue;
4937 }
4938 for (x=0; x < (ssize_t) image->columns; x++)
4939 {
4940 SetPixelAlpha(image,alpha,q);
4941 q+=GetPixelChannels(image);
4942 }
cristy23d198a2012-03-13 13:48:08 +00004943 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004944 }
cristy23d198a2012-03-13 13:48:08 +00004945 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004946 return(status);
4947}
4948
cristy387430f2012-02-07 13:09:46 +00004949MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4950 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004951{
4952 CacheInfo
4953 *cache_info;
4954
4955 VirtualPixelMethod
4956 method;
4957
4958 assert(image != (Image *) NULL);
4959 assert(image->signature == MagickSignature);
4960 if (image->debug != MagickFalse)
4961 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4962 assert(image->cache != (Cache) NULL);
4963 cache_info=(CacheInfo *) image->cache;
4964 assert(cache_info->signature == MagickSignature);
4965 method=cache_info->virtual_pixel_method;
4966 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy13c10082012-05-29 11:22:12 +00004967 if ((image->columns != 0) && (image->rows != 0))
4968 switch (virtual_pixel_method)
cristy387430f2012-02-07 13:09:46 +00004969 {
cristy13c10082012-05-29 11:22:12 +00004970 case BackgroundVirtualPixelMethod:
4971 {
4972 if ((image->background_color.matte != MagickFalse) &&
4973 (image->matte == MagickFalse))
4974 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy6386b792012-06-23 17:44:57 +00004975 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4976 (IsGrayColorspace(image->colorspace) != MagickFalse))
cristyb09db112012-07-11 12:04:31 +00004977 (void) TransformImageColorspace(image,RGBColorspace,exception);
cristy13c10082012-05-29 11:22:12 +00004978 break;
4979 }
4980 case TransparentVirtualPixelMethod:
4981 {
4982 if (image->matte == MagickFalse)
4983 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4984 break;
4985 }
4986 default:
4987 break;
cristy387430f2012-02-07 13:09:46 +00004988 }
cristy3ed852e2009-09-05 21:47:34 +00004989 return(method);
4990}
4991
4992/*
4993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4994% %
4995% %
4996% %
4997+ 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 %
4998% %
4999% %
5000% %
5001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5002%
5003% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5004% in-memory or disk cache. The method returns MagickTrue if the pixel region
5005% is synced, otherwise MagickFalse.
5006%
5007% The format of the SyncAuthenticPixelCacheNexus() method is:
5008%
5009% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5010% NexusInfo *nexus_info,ExceptionInfo *exception)
5011%
5012% A description of each parameter follows:
5013%
5014% o image: the image.
5015%
5016% o nexus_info: the cache nexus to sync.
5017%
5018% o exception: return any errors or warnings in this structure.
5019%
5020*/
cristya6577ff2011-09-02 19:54:26 +00005021MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005022 NexusInfo *nexus_info,ExceptionInfo *exception)
5023{
5024 CacheInfo
5025 *cache_info;
5026
5027 MagickBooleanType
5028 status;
5029
5030 /*
5031 Transfer pixels to the cache.
5032 */
5033 assert(image != (Image *) NULL);
5034 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005035 if (image->cache == (Cache) NULL)
5036 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5037 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005038 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005039 if (cache_info->type == UndefinedCache)
5040 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005041 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005042 return(MagickTrue);
5043 assert(cache_info->signature == MagickSignature);
5044 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005045 if ((cache_info->metacontent_extent != 0) &&
5046 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005047 return(MagickFalse);
5048 return(status);
5049}
5050
5051/*
5052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5053% %
5054% %
5055% %
5056+ S y n c A u t h e n t i c P i x e l C a c h e %
5057% %
5058% %
5059% %
5060%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5061%
5062% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5063% or disk cache. The method returns MagickTrue if the pixel region is synced,
5064% otherwise MagickFalse.
5065%
5066% The format of the SyncAuthenticPixelsCache() method is:
5067%
5068% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5069% ExceptionInfo *exception)
5070%
5071% A description of each parameter follows:
5072%
5073% o image: the image.
5074%
5075% o exception: return any errors or warnings in this structure.
5076%
5077*/
5078static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5079 ExceptionInfo *exception)
5080{
5081 CacheInfo
5082 *cache_info;
5083
cristy5c9e6f22010-09-17 17:31:01 +00005084 const int
5085 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005086
cristy4c08aed2011-07-01 19:47:50 +00005087 MagickBooleanType
5088 status;
5089
cristye7cc7cf2010-09-21 13:26:47 +00005090 assert(image != (Image *) NULL);
5091 assert(image->signature == MagickSignature);
5092 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005093 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005094 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005095 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005096 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5097 exception);
5098 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005099}
5100
5101/*
5102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5103% %
5104% %
5105% %
5106% S y n c A u t h e n t i c P i x e l s %
5107% %
5108% %
5109% %
5110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5111%
5112% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5113% The method returns MagickTrue if the pixel region is flushed, otherwise
5114% MagickFalse.
5115%
5116% The format of the SyncAuthenticPixels() method is:
5117%
5118% MagickBooleanType SyncAuthenticPixels(Image *image,
5119% ExceptionInfo *exception)
5120%
5121% A description of each parameter follows:
5122%
5123% o image: the image.
5124%
5125% o exception: return any errors or warnings in this structure.
5126%
5127*/
5128MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5129 ExceptionInfo *exception)
5130{
5131 CacheInfo
5132 *cache_info;
5133
cristy2036f5c2010-09-19 21:18:17 +00005134 const int
5135 id = GetOpenMPThreadId();
5136
cristy4c08aed2011-07-01 19:47:50 +00005137 MagickBooleanType
5138 status;
5139
cristy3ed852e2009-09-05 21:47:34 +00005140 assert(image != (Image *) NULL);
5141 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005142 assert(image->cache != (Cache) NULL);
5143 cache_info=(CacheInfo *) image->cache;
5144 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005145 if (cache_info->methods.sync_authentic_pixels_handler !=
5146 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005147 {
5148 status=cache_info->methods.sync_authentic_pixels_handler(image,
5149 exception);
5150 return(status);
5151 }
cristy2036f5c2010-09-19 21:18:17 +00005152 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005153 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5154 exception);
5155 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005156}
5157
5158/*
5159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5160% %
5161% %
5162% %
cristyd1dd6e42011-09-04 01:46:08 +00005163+ 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 +00005164% %
5165% %
5166% %
5167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5168%
5169% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5170% The method returns MagickTrue if the pixel region is flushed, otherwise
5171% MagickFalse.
5172%
5173% The format of the SyncImagePixelCache() method is:
5174%
5175% MagickBooleanType SyncImagePixelCache(Image *image,
5176% ExceptionInfo *exception)
5177%
5178% A description of each parameter follows:
5179%
5180% o image: the image.
5181%
5182% o exception: return any errors or warnings in this structure.
5183%
5184*/
cristyd1dd6e42011-09-04 01:46:08 +00005185MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005186 ExceptionInfo *exception)
5187{
5188 CacheInfo
5189 *cache_info;
5190
5191 assert(image != (Image *) NULL);
5192 assert(exception != (ExceptionInfo *) NULL);
5193 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5194 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5195}
5196
5197/*
5198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5199% %
5200% %
5201% %
cristy4c08aed2011-07-01 19:47:50 +00005202+ 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 +00005203% %
5204% %
5205% %
5206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5207%
cristy4c08aed2011-07-01 19:47:50 +00005208% WritePixelCacheMetacontent() writes the meta-content to the specified region
5209% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005210%
cristy4c08aed2011-07-01 19:47:50 +00005211% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005212%
cristy4c08aed2011-07-01 19:47:50 +00005213% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005214% NexusInfo *nexus_info,ExceptionInfo *exception)
5215%
5216% A description of each parameter follows:
5217%
5218% o cache_info: the pixel cache.
5219%
cristy4c08aed2011-07-01 19:47:50 +00005220% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005221%
5222% o exception: return any errors or warnings in this structure.
5223%
5224*/
cristy4c08aed2011-07-01 19:47:50 +00005225static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005226 NexusInfo *nexus_info,ExceptionInfo *exception)
5227{
5228 MagickOffsetType
5229 count,
5230 offset;
5231
5232 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005233 extent,
5234 length;
cristy3ed852e2009-09-05 21:47:34 +00005235
cristy4c08aed2011-07-01 19:47:50 +00005236 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005237 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005238
cristybb503372010-05-27 20:51:26 +00005239 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005240 y;
5241
cristybb503372010-05-27 20:51:26 +00005242 size_t
cristy3ed852e2009-09-05 21:47:34 +00005243 rows;
5244
cristy4c08aed2011-07-01 19:47:50 +00005245 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005246 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005247 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005248 return(MagickTrue);
5249 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5250 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005251 length=(MagickSizeType) nexus_info->region.width*
5252 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005253 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005254 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005255 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005256 switch (cache_info->type)
5257 {
5258 case MemoryCache:
5259 case MapCache:
5260 {
cristy4c08aed2011-07-01 19:47:50 +00005261 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005262 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005263
5264 /*
cristy4c08aed2011-07-01 19:47:50 +00005265 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005266 */
cristydd341db2010-03-04 19:06:38 +00005267 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005268 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005269 {
cristy48078b12010-09-23 17:11:01 +00005270 length=extent;
cristydd341db2010-03-04 19:06:38 +00005271 rows=1UL;
5272 }
cristy4c08aed2011-07-01 19:47:50 +00005273 q=(unsigned char *) cache_info->metacontent+offset*
5274 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005275 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005276 {
cristy8f036fe2010-09-18 02:02:00 +00005277 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005278 p+=nexus_info->region.width*cache_info->metacontent_extent;
5279 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005280 }
5281 break;
5282 }
5283 case DiskCache:
5284 {
5285 /*
cristy4c08aed2011-07-01 19:47:50 +00005286 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005287 */
5288 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5289 {
5290 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5291 cache_info->cache_filename);
5292 return(MagickFalse);
5293 }
cristydd341db2010-03-04 19:06:38 +00005294 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005295 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005296 {
cristy48078b12010-09-23 17:11:01 +00005297 length=extent;
cristydd341db2010-03-04 19:06:38 +00005298 rows=1UL;
5299 }
cristy48078b12010-09-23 17:11:01 +00005300 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005301 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005302 {
cristy48078b12010-09-23 17:11:01 +00005303 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005304 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005305 cache_info->metacontent_extent,length,(const unsigned char *) p);
5306 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005307 break;
cristy4c08aed2011-07-01 19:47:50 +00005308 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005309 offset+=cache_info->columns;
5310 }
cristyc11dace2012-01-24 16:39:46 +00005311 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5312 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005313 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005314 {
5315 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5316 cache_info->cache_filename);
5317 return(MagickFalse);
5318 }
5319 break;
5320 }
5321 default:
5322 break;
5323 }
5324 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005325 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005326 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005327 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005328 nexus_info->region.width,(double) nexus_info->region.height,(double)
5329 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005330 return(MagickTrue);
5331}
5332
5333/*
5334%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5335% %
5336% %
5337% %
5338+ W r i t e C a c h e P i x e l s %
5339% %
5340% %
5341% %
5342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5343%
5344% WritePixelCachePixels() writes image pixels to the specified region of the
5345% pixel cache.
5346%
5347% The format of the WritePixelCachePixels() method is:
5348%
5349% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5350% NexusInfo *nexus_info,ExceptionInfo *exception)
5351%
5352% A description of each parameter follows:
5353%
5354% o cache_info: the pixel cache.
5355%
5356% o nexus_info: the cache nexus to write the pixels.
5357%
5358% o exception: return any errors or warnings in this structure.
5359%
5360*/
5361static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5362 NexusInfo *nexus_info,ExceptionInfo *exception)
5363{
5364 MagickOffsetType
5365 count,
5366 offset;
5367
5368 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005369 extent,
5370 length;
cristy3ed852e2009-09-05 21:47:34 +00005371
cristy4c08aed2011-07-01 19:47:50 +00005372 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005373 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005374
cristybb503372010-05-27 20:51:26 +00005375 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005376 y;
5377
cristybb503372010-05-27 20:51:26 +00005378 size_t
cristy3ed852e2009-09-05 21:47:34 +00005379 rows;
5380
cristy4c08aed2011-07-01 19:47:50 +00005381 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005382 return(MagickTrue);
5383 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5384 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005385 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005386 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005387 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005388 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005389 p=nexus_info->pixels;
5390 switch (cache_info->type)
5391 {
5392 case MemoryCache:
5393 case MapCache:
5394 {
cristy4c08aed2011-07-01 19:47:50 +00005395 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005396 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005397
5398 /*
5399 Write pixels to memory.
5400 */
cristydd341db2010-03-04 19:06:38 +00005401 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005402 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005403 {
cristy48078b12010-09-23 17:11:01 +00005404 length=extent;
cristydd341db2010-03-04 19:06:38 +00005405 rows=1UL;
5406 }
cristyed231572011-07-14 02:18:59 +00005407 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005408 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005409 {
cristy8f036fe2010-09-18 02:02:00 +00005410 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005411 p+=nexus_info->region.width*cache_info->number_channels;
5412 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005413 }
5414 break;
5415 }
5416 case DiskCache:
5417 {
5418 /*
5419 Write pixels to disk.
5420 */
5421 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5422 {
5423 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5424 cache_info->cache_filename);
5425 return(MagickFalse);
5426 }
cristydd341db2010-03-04 19:06:38 +00005427 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005428 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005429 {
cristy48078b12010-09-23 17:11:01 +00005430 length=extent;
cristydd341db2010-03-04 19:06:38 +00005431 rows=1UL;
5432 }
cristybb503372010-05-27 20:51:26 +00005433 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005434 {
5435 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005436 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005437 p);
5438 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005439 break;
cristyed231572011-07-14 02:18:59 +00005440 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005441 offset+=cache_info->columns;
5442 }
cristyc11dace2012-01-24 16:39:46 +00005443 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5444 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005445 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005446 {
5447 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5448 cache_info->cache_filename);
5449 return(MagickFalse);
5450 }
5451 break;
5452 }
5453 default:
5454 break;
5455 }
5456 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005457 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005458 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005459 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005460 nexus_info->region.width,(double) nexus_info->region.height,(double)
5461 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005462 return(MagickTrue);
5463}