blob: 92ec430af81c66838ad1a5ab564b6704da8af442 [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
cristye42639a2012-08-23 01:53:24 +0000250 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
251 number_threads,sizeof(*nexus_info)));
cristy3ed852e2009-09-05 21:47:34 +0000252 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
cristy0bcbb402012-10-21 00:55:09 +0000554 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000555 {
cristy0bcbb402012-10-21 00:55:09 +0000556 count=0;
557 if (errno != EINTR)
558 break;
cristy3ed852e2009-09-05 21:47:34 +0000559 }
560 }
561#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563#endif
564 return(i);
565}
566
cristyf1832792012-05-08 18:38:18 +0000567static inline MagickOffsetType WritePixelCacheRegion(
568 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
569 const MagickSizeType length,const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000570{
571 register MagickOffsetType
572 i;
573
574 ssize_t
575 count;
576
577#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000578 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000579 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000580 {
cristyf84a1932010-01-03 18:00:18 +0000581 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000582 return((MagickOffsetType) -1);
583 }
584#endif
585 count=0;
586 for (i=0; i < (MagickOffsetType) length; i+=count)
587 {
588#if !defined(MAGICKCORE_HAVE_PWRITE)
589 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
590 (MagickSizeType) SSIZE_MAX));
591#else
592 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000593 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000594#endif
cristy0bcbb402012-10-21 00:55:09 +0000595 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000596 {
cristy0bcbb402012-10-21 00:55:09 +0000597 count=0;
598 if (errno != EINTR)
599 break;
cristy3ed852e2009-09-05 21:47:34 +0000600 }
601 }
602#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000603 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000604#endif
605 return(i);
606}
607
cristy4c08aed2011-07-01 19:47:50 +0000608static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000609 CacheInfo *cache_info,ExceptionInfo *exception)
610{
611 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000612 count;
cristy3ed852e2009-09-05 21:47:34 +0000613
cristy4c08aed2011-07-01 19:47:50 +0000614 register MagickOffsetType
615 i;
cristye076a6e2010-08-15 19:59:43 +0000616
cristybb503372010-05-27 20:51:26 +0000617 size_t
cristy4c08aed2011-07-01 19:47:50 +0000618 length;
cristy3ed852e2009-09-05 21:47:34 +0000619
cristy4c08aed2011-07-01 19:47:50 +0000620 unsigned char
621 *blob;
622
623 /*
624 Clone pixel cache (both caches on disk).
625 */
cristy3ed852e2009-09-05 21:47:34 +0000626 if (cache_info->debug != MagickFalse)
627 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000628 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000629 sizeof(*blob));
630 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000631 {
cristy4c08aed2011-07-01 19:47:50 +0000632 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000633 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000634 cache_info->filename);
635 return(MagickFalse);
636 }
cristy3dedf062011-07-02 14:07:40 +0000637 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000638 {
639 blob=(unsigned char *) RelinquishMagickMemory(blob);
640 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
641 cache_info->cache_filename);
642 return(MagickFalse);
643 }
cristy3dedf062011-07-02 14:07:40 +0000644 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000645 {
646 (void) ClosePixelCacheOnDisk(cache_info);
647 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000648 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
649 clone_info->cache_filename);
650 return(MagickFalse);
651 }
cristy4c08aed2011-07-01 19:47:50 +0000652 count=0;
653 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000654 {
cristy4c08aed2011-07-01 19:47:50 +0000655 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
656 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
657 blob);
658 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000659 {
cristy4c08aed2011-07-01 19:47:50 +0000660 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
661 cache_info->cache_filename);
662 break;
cristy3ed852e2009-09-05 21:47:34 +0000663 }
cristy4c08aed2011-07-01 19:47:50 +0000664 length=(size_t) count;
665 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
666 if ((MagickSizeType) count != length)
667 {
668 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
669 clone_info->cache_filename);
670 break;
671 }
672 }
673 (void) ClosePixelCacheOnDisk(clone_info);
674 (void) ClosePixelCacheOnDisk(cache_info);
675 blob=(unsigned char *) RelinquishMagickMemory(blob);
676 if (i < (MagickOffsetType) cache_info->length)
677 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
cristyfd24a062012-01-02 14:46:34 +0000681static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000682 CacheInfo *cache_info,ExceptionInfo *exception)
683{
684 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000685 count;
cristy3ed852e2009-09-05 21:47:34 +0000686
cristy4c08aed2011-07-01 19:47:50 +0000687 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000688 {
cristy3ed852e2009-09-05 21:47:34 +0000689 /*
cristy4c08aed2011-07-01 19:47:50 +0000690 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000691 */
cristy4c08aed2011-07-01 19:47:50 +0000692 if (cache_info->debug != MagickFalse)
693 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
694 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
695 cache_info->length);
696 return(MagickTrue);
697 }
698 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
699 {
700 /*
701 Clone pixel cache (one cache on disk, one in memory).
702 */
703 if (cache_info->debug != MagickFalse)
704 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
705 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000706 {
cristy4c08aed2011-07-01 19:47:50 +0000707 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000708 cache_info->cache_filename);
709 return(MagickFalse);
710 }
cristy4c08aed2011-07-01 19:47:50 +0000711 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
712 cache_info->length,(unsigned char *) clone_info->pixels);
713 (void) ClosePixelCacheOnDisk(cache_info);
714 if ((MagickSizeType) count != cache_info->length)
715 {
716 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
717 cache_info->cache_filename);
718 return(MagickFalse);
719 }
720 return(MagickTrue);
721 }
722 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
723 {
724 /*
725 Clone pixel cache (one cache on disk, one in memory).
726 */
727 if (clone_info->debug != MagickFalse)
728 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
729 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
730 {
731 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
732 clone_info->cache_filename);
733 return(MagickFalse);
734 }
735 count=WritePixelCacheRegion(clone_info,clone_info->offset,
736 clone_info->length,(unsigned char *) cache_info->pixels);
737 (void) ClosePixelCacheOnDisk(clone_info);
738 if ((MagickSizeType) count != clone_info->length)
739 {
740 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
741 clone_info->cache_filename);
742 return(MagickFalse);
743 }
744 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000745 }
746 /*
cristy4c08aed2011-07-01 19:47:50 +0000747 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000748 */
cristy4c08aed2011-07-01 19:47:50 +0000749 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000750}
751
cristyfd24a062012-01-02 14:46:34 +0000752static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000753 CacheInfo *cache_info,ExceptionInfo *exception)
754{
cristy4c08aed2011-07-01 19:47:50 +0000755 MagickBooleanType
756 status;
cristy3ed852e2009-09-05 21:47:34 +0000757
cristy4c08aed2011-07-01 19:47:50 +0000758 MagickOffsetType
759 cache_offset,
760 clone_offset,
761 count;
762
763 register ssize_t
764 x;
765
cristyfd24a062012-01-02 14:46:34 +0000766 register unsigned char
767 *p;
768
cristy4c08aed2011-07-01 19:47:50 +0000769 size_t
cristy3ed852e2009-09-05 21:47:34 +0000770 length;
771
cristy4c08aed2011-07-01 19:47:50 +0000772 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000773 y;
774
cristy4c08aed2011-07-01 19:47:50 +0000775 unsigned char
776 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000777
cristy4c08aed2011-07-01 19:47:50 +0000778 /*
779 Clone pixel cache (unoptimized).
780 */
cristy3ed852e2009-09-05 21:47:34 +0000781 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000782 {
cristy4c08aed2011-07-01 19:47:50 +0000783 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
784 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
785 else
786 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
787 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
788 else
789 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
790 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
791 else
792 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
793 }
cristyed231572011-07-14 02:18:59 +0000794 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
795 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000796 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000797 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000798 if (blob == (unsigned char *) NULL)
799 {
800 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000801 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000802 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000803 return(MagickFalse);
804 }
cristy4c08aed2011-07-01 19:47:50 +0000805 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
806 cache_offset=0;
807 clone_offset=0;
808 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000809 {
cristy4c08aed2011-07-01 19:47:50 +0000810 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000811 {
cristy4c08aed2011-07-01 19:47:50 +0000812 blob=(unsigned char *) RelinquishMagickMemory(blob);
813 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000814 cache_info->cache_filename);
815 return(MagickFalse);
816 }
cristy4c08aed2011-07-01 19:47:50 +0000817 cache_offset=cache_info->offset;
818 }
819 if (clone_info->type == DiskCache)
820 {
cristy3dedf062011-07-02 14:07:40 +0000821 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000822 {
cristy4c08aed2011-07-01 19:47:50 +0000823 blob=(unsigned char *) RelinquishMagickMemory(blob);
824 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
825 clone_info->cache_filename);
826 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000827 }
cristy4c08aed2011-07-01 19:47:50 +0000828 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000829 }
830 /*
cristy4c08aed2011-07-01 19:47:50 +0000831 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000832 */
cristy4c08aed2011-07-01 19:47:50 +0000833 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000834 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000835 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000836 {
cristy4c08aed2011-07-01 19:47:50 +0000837 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000838 {
cristy9e0719b2011-12-29 03:45:45 +0000839 register ssize_t
840 i;
841
cristy3ed852e2009-09-05 21:47:34 +0000842 /*
cristy4c08aed2011-07-01 19:47:50 +0000843 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000844 */
cristyed231572011-07-14 02:18:59 +0000845 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000846 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000847 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000848 else
849 {
cristyfd24a062012-01-02 14:46:34 +0000850 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000851 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000852 {
cristy4c08aed2011-07-01 19:47:50 +0000853 status=MagickFalse;
854 break;
cristy3ed852e2009-09-05 21:47:34 +0000855 }
856 }
cristy4c08aed2011-07-01 19:47:50 +0000857 cache_offset+=length;
858 if ((y < (ssize_t) clone_info->rows) &&
859 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000860 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000861 {
cristy9e0719b2011-12-29 03:45:45 +0000862 PixelChannel
863 channel;
864
865 PixelTrait
866 traits;
867
868 ssize_t
869 offset;
870
cristy4c08aed2011-07-01 19:47:50 +0000871 /*
cristy3b8fe922011-12-29 18:56:23 +0000872 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000873 */
cristy9e0719b2011-12-29 03:45:45 +0000874 channel=clone_info->channel_map[i].channel;
875 traits=cache_info->channel_map[channel].traits;
876 if (traits == UndefinedPixelTrait)
877 {
cristy0f4425e2011-12-31 20:33:02 +0000878 clone_offset+=sizeof(Quantum);
879 continue;
cristy9e0719b2011-12-29 03:45:45 +0000880 }
cristy0f4425e2011-12-31 20:33:02 +0000881 offset=cache_info->channel_map[channel].offset;
882 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000883 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
884 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000885 else
886 {
cristy0f4425e2011-12-31 20:33:02 +0000887 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000888 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000889 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000890 {
cristy0f4425e2011-12-31 20:33:02 +0000891 status=MagickFalse;
892 break;
cristy4c08aed2011-07-01 19:47:50 +0000893 }
894 }
cristy9e0719b2011-12-29 03:45:45 +0000895 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000896 }
897 }
cristyac245f82012-05-05 17:13:57 +0000898 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000899 {
900 /*
901 Set remaining columns as undefined.
902 */
cristy888e6132012-04-23 19:54:54 +0000903 length=clone_info->number_channels*sizeof(Quantum);
904 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
905 for ( ; x < (ssize_t) clone_info->columns; x++)
906 {
907 if (clone_info->type != DiskCache)
908 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
909 blob,length);
910 else
911 {
912 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
913 if ((MagickSizeType) count != length)
914 {
915 status=MagickFalse;
916 break;
cristye04362f2012-04-23 15:33:05 +0000917 }
cristy888e6132012-04-23 19:54:54 +0000918 }
919 clone_offset+=length;
920 }
cristye04362f2012-04-23 15:33:05 +0000921 }
cristy4c08aed2011-07-01 19:47:50 +0000922 }
cristyed231572011-07-14 02:18:59 +0000923 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000924 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
925 for ( ; y < (ssize_t) clone_info->rows; y++)
926 {
927 /*
cristy9e0719b2011-12-29 03:45:45 +0000928 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000929 */
930 for (x=0; x < (ssize_t) clone_info->columns; x++)
931 {
932 if (clone_info->type != DiskCache)
933 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
934 length);
935 else
936 {
937 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
938 if ((MagickSizeType) count != length)
939 {
940 status=MagickFalse;
941 break;
942 }
943 }
944 clone_offset+=length;
945 }
946 }
cristy9e0719b2011-12-29 03:45:45 +0000947 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000948 (clone_info->metacontent_extent != 0))
949 {
950 /*
951 Clone metacontent.
952 */
953 for (y=0; y < (ssize_t) cache_info->rows; y++)
954 {
955 for (x=0; x < (ssize_t) cache_info->columns; x++)
956 {
957 /*
958 Read a set of metacontent.
959 */
960 length=cache_info->metacontent_extent;
961 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000962 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000963 else
964 {
cristyfd24a062012-01-02 14:46:34 +0000965 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000966 if ((MagickSizeType) count != length)
967 {
968 status=MagickFalse;
969 break;
970 }
971 }
972 cache_offset+=length;
973 if ((y < (ssize_t) clone_info->rows) &&
974 (x < (ssize_t) clone_info->columns))
975 {
976 /*
977 Write a set of metacontent.
978 */
979 length=clone_info->metacontent_extent;
980 if (clone_info->type != DiskCache)
981 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000982 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000983 else
984 {
cristyfd24a062012-01-02 14:46:34 +0000985 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000986 if ((MagickSizeType) count != length)
987 {
988 status=MagickFalse;
989 break;
990 }
991 }
992 clone_offset+=length;
993 }
994 }
995 length=clone_info->metacontent_extent;
996 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
997 for ( ; x < (ssize_t) clone_info->columns; x++)
998 {
999 /*
cristy9e0719b2011-12-29 03:45:45 +00001000 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001001 */
1002 if (clone_info->type != DiskCache)
1003 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1004 blob,length);
1005 else
1006 {
cristy208b1002011-08-07 18:51:50 +00001007 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001008 if ((MagickSizeType) count != length)
1009 {
1010 status=MagickFalse;
1011 break;
1012 }
1013 }
1014 clone_offset+=length;
1015 }
1016 }
cristyac245f82012-05-05 17:13:57 +00001017 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001018 {
cristye04362f2012-04-23 15:33:05 +00001019 /*
1020 Set remaining rows as undefined.
1021 */
cristy888e6132012-04-23 19:54:54 +00001022 length=clone_info->metacontent_extent;
1023 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1024 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001025 {
cristy888e6132012-04-23 19:54:54 +00001026 for (x=0; x < (ssize_t) clone_info->columns; x++)
1027 {
1028 if (clone_info->type != DiskCache)
1029 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1030 blob,length);
1031 else
1032 {
1033 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1034 blob);
1035 if ((MagickSizeType) count != length)
1036 {
1037 status=MagickFalse;
1038 break;
1039 }
1040 }
1041 clone_offset+=length;
1042 }
cristye04362f2012-04-23 15:33:05 +00001043 }
cristy4c08aed2011-07-01 19:47:50 +00001044 }
cristy4c08aed2011-07-01 19:47:50 +00001045 }
1046 if (clone_info->type == DiskCache)
1047 (void) ClosePixelCacheOnDisk(clone_info);
1048 if (cache_info->type == DiskCache)
1049 (void) ClosePixelCacheOnDisk(cache_info);
1050 blob=(unsigned char *) RelinquishMagickMemory(blob);
1051 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001052}
1053
1054static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1055 CacheInfo *cache_info,ExceptionInfo *exception)
1056{
cristy3dfccb22011-12-28 21:47:20 +00001057 PixelChannelMap
1058 *p,
1059 *q;
1060
cristy5a7fbfb2010-11-06 16:10:59 +00001061 if (cache_info->type == PingCache)
1062 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001063 p=cache_info->channel_map;
1064 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001065 if ((cache_info->columns == clone_info->columns) &&
1066 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001067 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001068 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001069 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001070 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1071 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001072}
1073
1074/*
1075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076% %
1077% %
1078% %
1079+ C l o n e P i x e l C a c h e M e t h o d s %
1080% %
1081% %
1082% %
1083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084%
1085% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1086% another.
1087%
1088% The format of the ClonePixelCacheMethods() method is:
1089%
1090% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1091%
1092% A description of each parameter follows:
1093%
1094% o clone: Specifies a pointer to a Cache structure.
1095%
1096% o cache: the pixel cache.
1097%
1098*/
cristya6577ff2011-09-02 19:54:26 +00001099MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001100{
1101 CacheInfo
1102 *cache_info,
1103 *source_info;
1104
1105 assert(clone != (Cache) NULL);
1106 source_info=(CacheInfo *) clone;
1107 assert(source_info->signature == MagickSignature);
1108 if (source_info->debug != MagickFalse)
1109 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1110 source_info->filename);
1111 assert(cache != (Cache) NULL);
1112 cache_info=(CacheInfo *) cache;
1113 assert(cache_info->signature == MagickSignature);
1114 source_info->methods=cache_info->methods;
1115}
1116
1117/*
1118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119% %
1120% %
1121% %
1122+ D e s t r o y I m a g e P i x e l C a c h e %
1123% %
1124% %
1125% %
1126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127%
1128% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1129%
1130% The format of the DestroyImagePixelCache() method is:
1131%
1132% void DestroyImagePixelCache(Image *image)
1133%
1134% A description of each parameter follows:
1135%
1136% o image: the image.
1137%
1138*/
1139static void DestroyImagePixelCache(Image *image)
1140{
1141 assert(image != (Image *) NULL);
1142 assert(image->signature == MagickSignature);
1143 if (image->debug != MagickFalse)
1144 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1145 if (image->cache == (void *) NULL)
1146 return;
1147 image->cache=DestroyPixelCache(image->cache);
1148}
1149
1150/*
1151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152% %
1153% %
1154% %
1155+ D e s t r o y I m a g e P i x e l s %
1156% %
1157% %
1158% %
1159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1160%
1161% DestroyImagePixels() deallocates memory associated with the pixel cache.
1162%
1163% The format of the DestroyImagePixels() method is:
1164%
1165% void DestroyImagePixels(Image *image)
1166%
1167% A description of each parameter follows:
1168%
1169% o image: the image.
1170%
1171*/
1172MagickExport void DestroyImagePixels(Image *image)
1173{
1174 CacheInfo
1175 *cache_info;
1176
1177 assert(image != (const Image *) NULL);
1178 assert(image->signature == MagickSignature);
1179 if (image->debug != MagickFalse)
1180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1181 assert(image->cache != (Cache) NULL);
1182 cache_info=(CacheInfo *) image->cache;
1183 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001184 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1185 {
1186 cache_info->methods.destroy_pixel_handler(image);
1187 return;
1188 }
cristy2036f5c2010-09-19 21:18:17 +00001189 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001190}
1191
1192/*
1193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1194% %
1195% %
1196% %
1197+ D e s t r o y P i x e l C a c h e %
1198% %
1199% %
1200% %
1201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202%
1203% DestroyPixelCache() deallocates memory associated with the pixel cache.
1204%
1205% The format of the DestroyPixelCache() method is:
1206%
1207% Cache DestroyPixelCache(Cache cache)
1208%
1209% A description of each parameter follows:
1210%
1211% o cache: the pixel cache.
1212%
1213*/
1214
1215static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1216{
1217 switch (cache_info->type)
1218 {
1219 case MemoryCache:
1220 {
1221 if (cache_info->mapped == MagickFalse)
cristy9dd0b6f2012-08-01 14:38:43 +00001222 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
cristy3ed852e2009-09-05 21:47:34 +00001223 cache_info->pixels);
1224 else
cristy4c08aed2011-07-01 19:47:50 +00001225 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001226 (size_t) cache_info->length);
1227 RelinquishMagickResource(MemoryResource,cache_info->length);
1228 break;
1229 }
1230 case MapCache:
1231 {
cristy4c08aed2011-07-01 19:47:50 +00001232 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001233 cache_info->length);
1234 RelinquishMagickResource(MapResource,cache_info->length);
1235 }
1236 case DiskCache:
1237 {
1238 if (cache_info->file != -1)
1239 (void) ClosePixelCacheOnDisk(cache_info);
1240 RelinquishMagickResource(DiskResource,cache_info->length);
1241 break;
1242 }
1243 default:
1244 break;
1245 }
1246 cache_info->type=UndefinedCache;
1247 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001248 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001249}
1250
cristya6577ff2011-09-02 19:54:26 +00001251MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001252{
1253 CacheInfo
1254 *cache_info;
1255
cristy3ed852e2009-09-05 21:47:34 +00001256 assert(cache != (Cache) NULL);
1257 cache_info=(CacheInfo *) cache;
1258 assert(cache_info->signature == MagickSignature);
1259 if (cache_info->debug != MagickFalse)
1260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1261 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001262 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001263 cache_info->reference_count--;
1264 if (cache_info->reference_count != 0)
1265 {
cristyf84a1932010-01-03 18:00:18 +00001266 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001267 return((Cache) NULL);
1268 }
cristyf84a1932010-01-03 18:00:18 +00001269 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001270 if (cache_info->debug != MagickFalse)
1271 {
1272 char
1273 message[MaxTextExtent];
1274
cristyb51dff52011-05-19 16:55:47 +00001275 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001276 cache_info->filename);
1277 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1278 }
cristyc2e1bdd2009-09-10 23:43:34 +00001279 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1280 (cache_info->type != DiskCache)))
1281 RelinquishPixelCachePixels(cache_info);
1282 else
1283 {
1284 RelinquishPixelCachePixels(cache_info);
1285 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1286 }
cristy3ed852e2009-09-05 21:47:34 +00001287 *cache_info->cache_filename='\0';
1288 if (cache_info->nexus_info != (NexusInfo **) NULL)
1289 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1290 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001291 if (cache_info->random_info != (RandomInfo *) NULL)
1292 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001293 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1294 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1295 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1296 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001297 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001298 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001299 cache=(Cache) NULL;
1300 return(cache);
1301}
1302
1303/*
1304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305% %
1306% %
1307% %
1308+ D e s t r o y P i x e l C a c h e N e x u s %
1309% %
1310% %
1311% %
1312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313%
1314% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1315%
1316% The format of the DestroyPixelCacheNexus() method is:
1317%
1318% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001319% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001320%
1321% A description of each parameter follows:
1322%
1323% o nexus_info: the nexus to destroy.
1324%
1325% o number_threads: the number of nexus threads.
1326%
1327*/
1328
1329static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1330{
1331 if (nexus_info->mapped == MagickFalse)
cristy9dd0b6f2012-08-01 14:38:43 +00001332 (void) RelinquishAlignedMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001333 else
1334 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001335 nexus_info->cache=(Quantum *) NULL;
1336 nexus_info->pixels=(Quantum *) NULL;
1337 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001338 nexus_info->length=0;
1339 nexus_info->mapped=MagickFalse;
1340}
1341
cristya6577ff2011-09-02 19:54:26 +00001342MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001343 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001344{
cristybb503372010-05-27 20:51:26 +00001345 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001346 i;
1347
1348 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001349 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001350 {
cristy4c08aed2011-07-01 19:47:50 +00001351 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001352 RelinquishCacheNexusPixels(nexus_info[i]);
1353 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001354 }
cristye5f87c82012-02-14 12:44:17 +00001355 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001356 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001357 return(nexus_info);
1358}
1359
1360/*
1361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362% %
1363% %
1364% %
cristy4c08aed2011-07-01 19:47:50 +00001365% 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 +00001366% %
1367% %
1368% %
1369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370%
cristy4c08aed2011-07-01 19:47:50 +00001371% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1372% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1373% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001374%
cristy4c08aed2011-07-01 19:47:50 +00001375% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001376%
cristy4c08aed2011-07-01 19:47:50 +00001377% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001378%
1379% A description of each parameter follows:
1380%
1381% o image: the image.
1382%
1383*/
cristy4c08aed2011-07-01 19:47:50 +00001384MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001385{
1386 CacheInfo
1387 *cache_info;
1388
cristy5c9e6f22010-09-17 17:31:01 +00001389 const int
1390 id = GetOpenMPThreadId();
1391
cristy4c08aed2011-07-01 19:47:50 +00001392 void
1393 *metacontent;
1394
cristye7cc7cf2010-09-21 13:26:47 +00001395 assert(image != (const Image *) NULL);
1396 assert(image->signature == MagickSignature);
1397 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001398 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001399 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001400 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1401 (GetAuthenticMetacontentFromHandler) NULL)
1402 {
1403 metacontent=cache_info->methods.
1404 get_authentic_metacontent_from_handler(image);
1405 return(metacontent);
1406 }
cristy6ebe97c2010-07-03 01:17:28 +00001407 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001408 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1409 cache_info->nexus_info[id]);
1410 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001411}
1412
1413/*
1414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415% %
1416% %
1417% %
cristy4c08aed2011-07-01 19:47:50 +00001418+ 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 +00001419% %
1420% %
1421% %
1422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423%
cristy4c08aed2011-07-01 19:47:50 +00001424% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1425% with the last call to QueueAuthenticPixelsCache() or
1426% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001427%
cristy4c08aed2011-07-01 19:47:50 +00001428% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001429%
cristy4c08aed2011-07-01 19:47:50 +00001430% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001431%
1432% A description of each parameter follows:
1433%
1434% o image: the image.
1435%
1436*/
cristy4c08aed2011-07-01 19:47:50 +00001437static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001438{
1439 CacheInfo
1440 *cache_info;
1441
cristy2036f5c2010-09-19 21:18:17 +00001442 const int
1443 id = GetOpenMPThreadId();
1444
cristy4c08aed2011-07-01 19:47:50 +00001445 void
1446 *metacontent;
1447
cristy3ed852e2009-09-05 21:47:34 +00001448 assert(image != (const Image *) NULL);
1449 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001450 assert(image->cache != (Cache) NULL);
1451 cache_info=(CacheInfo *) image->cache;
1452 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001453 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001454 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1455 cache_info->nexus_info[id]);
1456 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001457}
1458
1459/*
1460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1461% %
1462% %
1463% %
1464+ 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 %
1465% %
1466% %
1467% %
1468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1469%
1470% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1471% disk pixel cache as defined by the geometry parameters. A pointer to the
1472% pixels is returned if the pixels are transferred, otherwise a NULL is
1473% returned.
1474%
1475% The format of the GetAuthenticPixelCacheNexus() method is:
1476%
cristy4c08aed2011-07-01 19:47:50 +00001477% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001478% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001479% NexusInfo *nexus_info,ExceptionInfo *exception)
1480%
1481% A description of each parameter follows:
1482%
1483% o image: the image.
1484%
1485% o x,y,columns,rows: These values define the perimeter of a region of
1486% pixels.
1487%
1488% o nexus_info: the cache nexus to return.
1489%
1490% o exception: return any errors or warnings in this structure.
1491%
1492*/
1493
cristy7f69b802012-05-08 16:39:59 +00001494static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001495 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001496{
cristy4c08aed2011-07-01 19:47:50 +00001497 MagickBooleanType
1498 status;
1499
cristy3ed852e2009-09-05 21:47:34 +00001500 MagickOffsetType
1501 offset;
1502
cristy73724512010-04-12 14:43:14 +00001503 if (cache_info->type == PingCache)
1504 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001505 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1506 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001507 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001508 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001509 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001510}
1511
cristya6577ff2011-09-02 19:54:26 +00001512MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001513 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001514 NexusInfo *nexus_info,ExceptionInfo *exception)
1515{
1516 CacheInfo
1517 *cache_info;
1518
cristy4c08aed2011-07-01 19:47:50 +00001519 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001520 *q;
cristy3ed852e2009-09-05 21:47:34 +00001521
1522 /*
1523 Transfer pixels from the cache.
1524 */
1525 assert(image != (Image *) NULL);
1526 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001527 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1528 exception);
cristyacd2ed22011-08-30 01:44:23 +00001529 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001530 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001531 cache_info=(CacheInfo *) image->cache;
1532 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001533 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001534 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001535 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001536 return((Quantum *) NULL);
1537 if (cache_info->metacontent_extent != 0)
1538 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1539 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001540 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001541}
1542
1543/*
1544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1545% %
1546% %
1547% %
1548+ 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 %
1549% %
1550% %
1551% %
1552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1553%
1554% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1555% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1556%
1557% The format of the GetAuthenticPixelsFromCache() method is:
1558%
cristy4c08aed2011-07-01 19:47:50 +00001559% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001560%
1561% A description of each parameter follows:
1562%
1563% o image: the image.
1564%
1565*/
cristy4c08aed2011-07-01 19:47:50 +00001566static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001567{
1568 CacheInfo
1569 *cache_info;
1570
cristy5c9e6f22010-09-17 17:31:01 +00001571 const int
1572 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001573
cristye7cc7cf2010-09-21 13:26:47 +00001574 assert(image != (const Image *) NULL);
1575 assert(image->signature == MagickSignature);
1576 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001577 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001578 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001579 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001580 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001581}
1582
1583/*
1584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1585% %
1586% %
1587% %
1588% G e t A u t h e n t i c P i x e l Q u e u e %
1589% %
1590% %
1591% %
1592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593%
cristy4c08aed2011-07-01 19:47:50 +00001594% GetAuthenticPixelQueue() returns the authentic pixels associated
1595% corresponding with the last call to QueueAuthenticPixels() or
1596% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001597%
1598% The format of the GetAuthenticPixelQueue() method is:
1599%
cristy4c08aed2011-07-01 19:47:50 +00001600% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001601%
1602% A description of each parameter follows:
1603%
1604% o image: the image.
1605%
1606*/
cristy4c08aed2011-07-01 19:47:50 +00001607MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001608{
1609 CacheInfo
1610 *cache_info;
1611
cristy2036f5c2010-09-19 21:18:17 +00001612 const int
1613 id = GetOpenMPThreadId();
1614
cristy3ed852e2009-09-05 21:47:34 +00001615 assert(image != (const Image *) NULL);
1616 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001617 assert(image->cache != (Cache) NULL);
1618 cache_info=(CacheInfo *) image->cache;
1619 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001620 if (cache_info->methods.get_authentic_pixels_from_handler !=
1621 (GetAuthenticPixelsFromHandler) NULL)
1622 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001623 assert(id < (int) cache_info->number_threads);
1624 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001625}
1626
1627/*
1628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629% %
1630% %
1631% %
1632% G e t A u t h e n t i c P i x e l s %
1633% %
1634% %
cristy4c08aed2011-07-01 19:47:50 +00001635% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001636%
1637% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001638% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001639% representing the region is returned, otherwise NULL is returned.
1640%
1641% The returned pointer may point to a temporary working copy of the pixels
1642% or it may point to the original pixels in memory. Performance is maximized
1643% if the selected region is part of one row, or one or more full rows, since
1644% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001645% if the image is in memory, or in a memory-mapped file. The returned pointer
1646% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001647%
1648% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001649% Quantum. If the image has corresponding metacontent,call
1650% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1651% meta-content corresponding to the region. Once the Quantum array has
1652% been updated, the changes must be saved back to the underlying image using
1653% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001654%
1655% The format of the GetAuthenticPixels() method is:
1656%
cristy4c08aed2011-07-01 19:47:50 +00001657% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001658% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001659% ExceptionInfo *exception)
1660%
1661% A description of each parameter follows:
1662%
1663% o image: the image.
1664%
1665% o x,y,columns,rows: These values define the perimeter of a region of
1666% pixels.
1667%
1668% o exception: return any errors or warnings in this structure.
1669%
1670*/
cristy4c08aed2011-07-01 19:47:50 +00001671MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001672 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001673 ExceptionInfo *exception)
1674{
1675 CacheInfo
1676 *cache_info;
1677
cristy2036f5c2010-09-19 21:18:17 +00001678 const int
1679 id = GetOpenMPThreadId();
1680
cristy4c08aed2011-07-01 19:47:50 +00001681 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001682 *q;
cristy4c08aed2011-07-01 19:47:50 +00001683
cristy3ed852e2009-09-05 21:47:34 +00001684 assert(image != (Image *) NULL);
1685 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001686 assert(image->cache != (Cache) NULL);
1687 cache_info=(CacheInfo *) image->cache;
1688 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001689 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001690 (GetAuthenticPixelsHandler) NULL)
1691 {
cristyacd2ed22011-08-30 01:44:23 +00001692 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1693 exception);
1694 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001695 }
cristy2036f5c2010-09-19 21:18:17 +00001696 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001697 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001698 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001699 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001700}
1701
1702/*
1703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1704% %
1705% %
1706% %
1707+ G e t A u t h e n t i c P i x e l s C a c h e %
1708% %
1709% %
1710% %
1711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1712%
1713% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1714% as defined by the geometry parameters. A pointer to the pixels is returned
1715% if the pixels are transferred, otherwise a NULL is returned.
1716%
1717% The format of the GetAuthenticPixelsCache() method is:
1718%
cristy4c08aed2011-07-01 19:47:50 +00001719% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001720% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001721% ExceptionInfo *exception)
1722%
1723% A description of each parameter follows:
1724%
1725% o image: the image.
1726%
1727% o x,y,columns,rows: These values define the perimeter of a region of
1728% pixels.
1729%
1730% o exception: return any errors or warnings in this structure.
1731%
1732*/
cristy4c08aed2011-07-01 19:47:50 +00001733static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001734 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001735 ExceptionInfo *exception)
1736{
1737 CacheInfo
1738 *cache_info;
1739
cristy5c9e6f22010-09-17 17:31:01 +00001740 const int
1741 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001742
cristy4c08aed2011-07-01 19:47:50 +00001743 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001744 *q;
cristy4c08aed2011-07-01 19:47:50 +00001745
cristye7cc7cf2010-09-21 13:26:47 +00001746 assert(image != (const Image *) NULL);
1747 assert(image->signature == MagickSignature);
1748 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001749 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001750 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001751 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001752 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001753 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001754 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001755 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001756 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001757}
1758
1759/*
1760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761% %
1762% %
1763% %
1764+ G e t I m a g e E x t e n t %
1765% %
1766% %
1767% %
1768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769%
cristy4c08aed2011-07-01 19:47:50 +00001770% GetImageExtent() returns the extent of the pixels associated corresponding
1771% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001772%
1773% The format of the GetImageExtent() method is:
1774%
1775% MagickSizeType GetImageExtent(const Image *image)
1776%
1777% A description of each parameter follows:
1778%
1779% o image: the image.
1780%
1781*/
1782MagickExport MagickSizeType GetImageExtent(const Image *image)
1783{
1784 CacheInfo
1785 *cache_info;
1786
cristy5c9e6f22010-09-17 17:31:01 +00001787 const int
1788 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001789
cristy3ed852e2009-09-05 21:47:34 +00001790 assert(image != (Image *) NULL);
1791 assert(image->signature == MagickSignature);
1792 if (image->debug != MagickFalse)
1793 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1794 assert(image->cache != (Cache) NULL);
1795 cache_info=(CacheInfo *) image->cache;
1796 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001797 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001798 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001799}
1800
1801/*
1802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1803% %
1804% %
1805% %
1806+ G e t I m a g e P i x e l C a c h e %
1807% %
1808% %
1809% %
1810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1811%
1812% GetImagePixelCache() ensures that there is only a single reference to the
1813% pixel cache to be modified, updating the provided cache pointer to point to
1814% a clone of the original pixel cache if necessary.
1815%
1816% The format of the GetImagePixelCache method is:
1817%
1818% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1819% ExceptionInfo *exception)
1820%
1821% A description of each parameter follows:
1822%
1823% o image: the image.
1824%
1825% o clone: any value other than MagickFalse clones the cache pixels.
1826%
1827% o exception: return any errors or warnings in this structure.
1828%
1829*/
cristyaf894d72011-08-06 23:03:10 +00001830
cristyf1832792012-05-08 18:38:18 +00001831static inline MagickBooleanType ValidatePixelCacheMorphology(
1832 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001833{
cristyf1832792012-05-08 18:38:18 +00001834 const CacheInfo
1835 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001836
cristyf1832792012-05-08 18:38:18 +00001837 const PixelChannelMap
1838 *restrict p,
1839 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001840
cristy3ed852e2009-09-05 21:47:34 +00001841 /*
1842 Does the image match the pixel cache morphology?
1843 */
1844 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001845 p=image->channel_map;
1846 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001847 if ((image->storage_class != cache_info->storage_class) ||
1848 (image->colorspace != cache_info->colorspace) ||
cristy8a46d822012-08-28 23:32:39 +00001849 (image->alpha_trait != cache_info->alpha_trait) ||
cristy183a5c72012-01-30 01:40:35 +00001850 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001851 (image->columns != cache_info->columns) ||
1852 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001853 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001854 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001855 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001856 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001857 return(MagickFalse);
1858 return(MagickTrue);
1859}
1860
cristycd01fae2011-08-06 23:52:42 +00001861static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1862 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001863{
1864 CacheInfo
1865 *cache_info;
1866
cristy3ed852e2009-09-05 21:47:34 +00001867 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001868 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001869 status;
1870
cristy50a10922010-02-15 18:35:25 +00001871 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001872 cpu_throttle = 0,
1873 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001874 time_limit = 0;
1875
cristy1ea34962010-07-01 19:49:21 +00001876 static time_t
cristy208b1002011-08-07 18:51:50 +00001877 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001878
cristyc4f9f132010-03-04 18:50:01 +00001879 status=MagickTrue;
1880 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001881 if (cpu_throttle == 0)
1882 {
1883 char
1884 *limit;
1885
1886 /*
1887 Set CPU throttle in milleseconds.
1888 */
1889 cpu_throttle=MagickResourceInfinity;
1890 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1891 if (limit == (char *) NULL)
1892 limit=GetPolicyValue("throttle");
1893 if (limit != (char *) NULL)
1894 {
1895 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1896 limit=DestroyString(limit);
1897 }
1898 }
1899 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1900 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001901 if (time_limit == 0)
1902 {
cristy6ebe97c2010-07-03 01:17:28 +00001903 /*
1904 Set the exire time in seconds.
1905 */
cristy1ea34962010-07-01 19:49:21 +00001906 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001907 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001908 }
1909 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001910 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001911 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001912 assert(image->cache != (Cache) NULL);
1913 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001914 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001915 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001916 {
cristyceb55ee2010-11-06 16:05:49 +00001917 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001918 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001919 {
cristyceb55ee2010-11-06 16:05:49 +00001920 Image
1921 clone_image;
1922
1923 CacheInfo
1924 *clone_info;
1925
1926 /*
1927 Clone pixel cache.
1928 */
1929 clone_image=(*image);
1930 clone_image.semaphore=AllocateSemaphoreInfo();
1931 clone_image.reference_count=1;
1932 clone_image.cache=ClonePixelCache(cache_info);
1933 clone_info=(CacheInfo *) clone_image.cache;
1934 status=OpenPixelCache(&clone_image,IOMode,exception);
1935 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001936 {
cristy5a7fbfb2010-11-06 16:10:59 +00001937 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001938 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001939 if (status != MagickFalse)
1940 {
cristy979bf772011-08-08 00:04:15 +00001941 if (cache_info->mode == ReadMode)
1942 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001943 destroy=MagickTrue;
1944 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001945 }
1946 }
cristyceb55ee2010-11-06 16:05:49 +00001947 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001948 }
cristyceb55ee2010-11-06 16:05:49 +00001949 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001950 }
cristy4320e0e2009-09-10 15:00:08 +00001951 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001952 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001953 if (status != MagickFalse)
1954 {
1955 /*
1956 Ensure the image matches the pixel cache morphology.
1957 */
1958 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001959 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001960 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001961 {
1962 status=OpenPixelCache(image,IOMode,exception);
1963 cache_info=(CacheInfo *) image->cache;
1964 if (cache_info->type == DiskCache)
1965 (void) ClosePixelCacheOnDisk(cache_info);
1966 }
cristy3ed852e2009-09-05 21:47:34 +00001967 }
cristyf84a1932010-01-03 18:00:18 +00001968 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001969 if (status == MagickFalse)
1970 return((Cache) NULL);
1971 return(image->cache);
1972}
1973
1974/*
1975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1976% %
1977% %
1978% %
cristyce1fe792012-05-16 15:58:37 +00001979+ G e t I m a g e P i x e l C a c h e T y p e %
1980% %
1981% %
1982% %
1983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1984%
1985% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1986% DiskCache, MemoryCache, MapCache, or PingCache.
1987%
1988% The format of the GetImagePixelCacheType() method is:
1989%
cristy5bef4cd2012-05-17 18:08:56 +00001990% CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001991%
1992% A description of each parameter follows:
1993%
1994% o image: the image.
1995%
1996*/
cristy5bef4cd2012-05-17 18:08:56 +00001997MagickExport CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001998{
cristy238287d2012-05-17 18:16:56 +00001999 CacheInfo
2000 *cache_info;
2001
2002 assert(image != (Image *) NULL);
2003 assert(image->signature == MagickSignature);
2004 assert(image->cache != (Cache) NULL);
2005 cache_info=(CacheInfo *) image->cache;
2006 assert(cache_info->signature == MagickSignature);
2007 return(cache_info->type);
cristyce1fe792012-05-16 15:58:37 +00002008}
2009
2010/*
2011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2012% %
2013% %
2014% %
cristy3ed852e2009-09-05 21:47:34 +00002015% G e t O n e A u t h e n t i c P i x e l %
2016% %
2017% %
2018% %
2019%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2020%
2021% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2022% location. The image background color is returned if an error occurs.
2023%
2024% The format of the GetOneAuthenticPixel() method is:
2025%
cristybb503372010-05-27 20:51:26 +00002026% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002027% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002028%
2029% A description of each parameter follows:
2030%
2031% o image: the image.
2032%
2033% o x,y: These values define the location of the pixel to return.
2034%
2035% o pixel: return a pixel at the specified (x,y) location.
2036%
2037% o exception: return any errors or warnings in this structure.
2038%
2039*/
cristyacbbb7c2010-06-30 18:56:48 +00002040MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002041 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002042{
2043 CacheInfo
2044 *cache_info;
2045
cristy4c08aed2011-07-01 19:47:50 +00002046 register Quantum
2047 *q;
cristy2036f5c2010-09-19 21:18:17 +00002048
cristy2ed42f62011-10-02 19:49:57 +00002049 register ssize_t
2050 i;
2051
cristy3ed852e2009-09-05 21:47:34 +00002052 assert(image != (Image *) NULL);
2053 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002054 assert(image->cache != (Cache) NULL);
2055 cache_info=(CacheInfo *) image->cache;
2056 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002057 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002058 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2059 (GetOneAuthenticPixelFromHandler) NULL)
2060 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2061 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002062 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2063 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002064 {
cristy9e0719b2011-12-29 03:45:45 +00002065 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2066 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2067 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2068 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2069 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002070 return(MagickFalse);
2071 }
2072 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2073 {
2074 PixelChannel
2075 channel;
2076
cristycf1296e2012-08-26 23:40:49 +00002077 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002078 pixel[channel]=q[i];
2079 }
cristy2036f5c2010-09-19 21:18:17 +00002080 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002081}
2082
2083/*
2084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2085% %
2086% %
2087% %
2088+ G e t O n e A u t h e n t i c P i x e l F r o m C a c h e %
2089% %
2090% %
2091% %
2092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2093%
2094% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2095% location. The image background color is returned if an error occurs.
2096%
2097% The format of the GetOneAuthenticPixelFromCache() method is:
2098%
2099% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002100% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002101% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002102%
2103% A description of each parameter follows:
2104%
2105% o image: the image.
2106%
2107% o x,y: These values define the location of the pixel to return.
2108%
2109% o pixel: return a pixel at the specified (x,y) location.
2110%
2111% o exception: return any errors or warnings in this structure.
2112%
2113*/
2114static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002115 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002116{
cristy098f78c2010-09-23 17:28:44 +00002117 CacheInfo
2118 *cache_info;
2119
2120 const int
2121 id = GetOpenMPThreadId();
2122
cristy4c08aed2011-07-01 19:47:50 +00002123 register Quantum
2124 *q;
cristy3ed852e2009-09-05 21:47:34 +00002125
cristy2ed42f62011-10-02 19:49:57 +00002126 register ssize_t
2127 i;
2128
cristy0158a4b2010-09-20 13:59:45 +00002129 assert(image != (const Image *) NULL);
2130 assert(image->signature == MagickSignature);
2131 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002132 cache_info=(CacheInfo *) image->cache;
2133 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002134 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002135 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002136 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2137 exception);
2138 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002139 {
cristy9e0719b2011-12-29 03:45:45 +00002140 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2141 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2142 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2143 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2144 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002145 return(MagickFalse);
2146 }
2147 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2148 {
2149 PixelChannel
2150 channel;
2151
cristycf1296e2012-08-26 23:40:49 +00002152 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002153 pixel[channel]=q[i];
2154 }
cristy3ed852e2009-09-05 21:47:34 +00002155 return(MagickTrue);
2156}
2157
2158/*
2159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2160% %
2161% %
2162% %
cristy3ed852e2009-09-05 21:47:34 +00002163% G e t O n e V i r t u a l P i x e l %
2164% %
2165% %
2166% %
2167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2168%
2169% GetOneVirtualPixel() returns a single virtual pixel at the specified
2170% (x,y) location. The image background color is returned if an error occurs.
2171% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2172%
2173% The format of the GetOneVirtualPixel() method is:
2174%
cristybb503372010-05-27 20:51:26 +00002175% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002176% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002177%
2178% A description of each parameter follows:
2179%
2180% o image: the image.
2181%
2182% o x,y: These values define the location of the pixel to return.
2183%
2184% o pixel: return a pixel at the specified (x,y) location.
2185%
2186% o exception: return any errors or warnings in this structure.
2187%
2188*/
2189MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002190 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002191{
cristy3ed852e2009-09-05 21:47:34 +00002192 CacheInfo
2193 *cache_info;
2194
cristy0158a4b2010-09-20 13:59:45 +00002195 const int
2196 id = GetOpenMPThreadId();
2197
cristy4c08aed2011-07-01 19:47:50 +00002198 const Quantum
2199 *p;
cristy2036f5c2010-09-19 21:18:17 +00002200
cristy2ed42f62011-10-02 19:49:57 +00002201 register ssize_t
2202 i;
2203
cristy3ed852e2009-09-05 21:47:34 +00002204 assert(image != (const Image *) NULL);
2205 assert(image->signature == MagickSignature);
2206 assert(image->cache != (Cache) NULL);
2207 cache_info=(CacheInfo *) image->cache;
2208 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002209 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002210 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2211 (GetOneVirtualPixelFromHandler) NULL)
2212 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2213 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002214 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002215 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002216 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002217 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002218 {
cristy9e0719b2011-12-29 03:45:45 +00002219 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2220 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2221 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2222 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2223 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002224 return(MagickFalse);
2225 }
2226 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2227 {
2228 PixelChannel
2229 channel;
2230
cristycf1296e2012-08-26 23:40:49 +00002231 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002232 pixel[channel]=p[i];
2233 }
cristy2036f5c2010-09-19 21:18:17 +00002234 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002235}
2236
2237/*
2238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2239% %
2240% %
2241% %
2242+ G e t O n e V i r t u a l P i x e l F r o m C a c h e %
2243% %
2244% %
2245% %
2246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247%
2248% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2249% specified (x,y) location. The image background color is returned if an
2250% error occurs.
2251%
2252% The format of the GetOneVirtualPixelFromCache() method is:
2253%
2254% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002255% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002256% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002257%
2258% A description of each parameter follows:
2259%
2260% o image: the image.
2261%
2262% o virtual_pixel_method: the virtual pixel method.
2263%
2264% o x,y: These values define the location of the pixel to return.
2265%
2266% o pixel: return a pixel at the specified (x,y) location.
2267%
2268% o exception: return any errors or warnings in this structure.
2269%
2270*/
2271static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002272 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002273 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002274{
cristy0158a4b2010-09-20 13:59:45 +00002275 CacheInfo
2276 *cache_info;
2277
2278 const int
2279 id = GetOpenMPThreadId();
2280
cristy4c08aed2011-07-01 19:47:50 +00002281 const Quantum
2282 *p;
cristy3ed852e2009-09-05 21:47:34 +00002283
cristy2ed42f62011-10-02 19:49:57 +00002284 register ssize_t
2285 i;
2286
cristye7cc7cf2010-09-21 13:26:47 +00002287 assert(image != (const Image *) NULL);
2288 assert(image->signature == MagickSignature);
2289 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002290 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002291 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002292 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002293 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002294 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002295 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002296 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002297 {
cristy9e0719b2011-12-29 03:45:45 +00002298 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2299 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2300 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2301 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2302 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002303 return(MagickFalse);
2304 }
2305 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2306 {
2307 PixelChannel
2308 channel;
2309
cristycf1296e2012-08-26 23:40:49 +00002310 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002311 pixel[channel]=p[i];
2312 }
cristy3ed852e2009-09-05 21:47:34 +00002313 return(MagickTrue);
2314}
2315
2316/*
2317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2318% %
2319% %
2320% %
cristy3aa93752011-12-18 15:54:24 +00002321% G e t O n e V i r t u a l P i x e l I n f o %
2322% %
2323% %
2324% %
2325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2326%
2327% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2328% location. The image background color is returned if an error occurs. If
2329% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2330%
2331% The format of the GetOneVirtualPixelInfo() method is:
2332%
2333% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2334% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2335% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2336%
2337% A description of each parameter follows:
2338%
2339% o image: the image.
2340%
2341% o virtual_pixel_method: the virtual pixel method.
2342%
2343% o x,y: these values define the location of the pixel to return.
2344%
2345% o pixel: return a pixel at the specified (x,y) location.
2346%
2347% o exception: return any errors or warnings in this structure.
2348%
2349*/
2350MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2351 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2352 PixelInfo *pixel,ExceptionInfo *exception)
2353{
2354 CacheInfo
2355 *cache_info;
2356
2357 const int
2358 id = GetOpenMPThreadId();
2359
2360 register const Quantum
2361 *p;
2362
2363 assert(image != (const Image *) NULL);
2364 assert(image->signature == MagickSignature);
2365 assert(image->cache != (Cache) NULL);
2366 cache_info=(CacheInfo *) image->cache;
2367 assert(cache_info->signature == MagickSignature);
2368 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002369 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002370 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2371 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002372 if (p == (const Quantum *) NULL)
2373 return(MagickFalse);
2374 GetPixelInfoPixel(image,p,pixel);
2375 return(MagickTrue);
2376}
2377
2378/*
2379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380% %
2381% %
2382% %
cristy3ed852e2009-09-05 21:47:34 +00002383+ G e t P i x e l C a c h e C o l o r s p a c e %
2384% %
2385% %
2386% %
2387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388%
2389% GetPixelCacheColorspace() returns the class type of the pixel cache.
2390%
2391% The format of the GetPixelCacheColorspace() method is:
2392%
2393% Colorspace GetPixelCacheColorspace(Cache cache)
2394%
2395% A description of each parameter follows:
2396%
2397% o cache: the pixel cache.
2398%
2399*/
cristya6577ff2011-09-02 19:54:26 +00002400MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002401{
2402 CacheInfo
2403 *cache_info;
2404
2405 assert(cache != (Cache) NULL);
2406 cache_info=(CacheInfo *) cache;
2407 assert(cache_info->signature == MagickSignature);
2408 if (cache_info->debug != MagickFalse)
2409 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2410 cache_info->filename);
2411 return(cache_info->colorspace);
2412}
2413
2414/*
2415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2416% %
2417% %
2418% %
2419+ G e t P i x e l C a c h e M e t h o d s %
2420% %
2421% %
2422% %
2423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2424%
2425% GetPixelCacheMethods() initializes the CacheMethods structure.
2426%
2427% The format of the GetPixelCacheMethods() method is:
2428%
2429% void GetPixelCacheMethods(CacheMethods *cache_methods)
2430%
2431% A description of each parameter follows:
2432%
2433% o cache_methods: Specifies a pointer to a CacheMethods structure.
2434%
2435*/
cristya6577ff2011-09-02 19:54:26 +00002436MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002437{
2438 assert(cache_methods != (CacheMethods *) NULL);
2439 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2440 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2441 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002442 cache_methods->get_virtual_metacontent_from_handler=
2443 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002444 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2445 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002446 cache_methods->get_authentic_metacontent_from_handler=
2447 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002448 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2449 cache_methods->get_one_authentic_pixel_from_handler=
2450 GetOneAuthenticPixelFromCache;
2451 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2452 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2453 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2454}
2455
2456/*
2457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2458% %
2459% %
2460% %
2461+ G e t P i x e l C a c h e N e x u s E x t e n t %
2462% %
2463% %
2464% %
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466%
cristy4c08aed2011-07-01 19:47:50 +00002467% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2468% corresponding with the last call to SetPixelCacheNexusPixels() or
2469% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002470%
2471% The format of the GetPixelCacheNexusExtent() method is:
2472%
2473% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2474% NexusInfo *nexus_info)
2475%
2476% A description of each parameter follows:
2477%
2478% o nexus_info: the nexus info.
2479%
2480*/
cristya6577ff2011-09-02 19:54:26 +00002481MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002482 NexusInfo *nexus_info)
2483{
2484 CacheInfo
2485 *cache_info;
2486
2487 MagickSizeType
2488 extent;
2489
cristy9f027d12011-09-21 01:17:17 +00002490 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002491 cache_info=(CacheInfo *) cache;
2492 assert(cache_info->signature == MagickSignature);
2493 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2494 if (extent == 0)
2495 return((MagickSizeType) cache_info->columns*cache_info->rows);
2496 return(extent);
2497}
2498
2499/*
2500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501% %
2502% %
2503% %
cristy4c08aed2011-07-01 19:47:50 +00002504+ G e t P i x e l C a c h e N e x u s M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002505% %
2506% %
2507% %
2508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2509%
cristy4c08aed2011-07-01 19:47:50 +00002510% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2511% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002512%
cristy4c08aed2011-07-01 19:47:50 +00002513% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002514%
cristy4c08aed2011-07-01 19:47:50 +00002515% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002516% NexusInfo *nexus_info)
2517%
2518% A description of each parameter follows:
2519%
2520% o cache: the pixel cache.
2521%
cristy4c08aed2011-07-01 19:47:50 +00002522% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002523%
2524*/
cristya6577ff2011-09-02 19:54:26 +00002525MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002526 NexusInfo *nexus_info)
2527{
2528 CacheInfo
2529 *cache_info;
2530
cristy9f027d12011-09-21 01:17:17 +00002531 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002532 cache_info=(CacheInfo *) cache;
2533 assert(cache_info->signature == MagickSignature);
2534 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002535 return((void *) NULL);
2536 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002537}
2538
2539/*
2540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2541% %
2542% %
2543% %
2544+ G e t P i x e l C a c h e N e x u s P i x e l s %
2545% %
2546% %
2547% %
2548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549%
2550% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2551% cache nexus.
2552%
2553% The format of the GetPixelCacheNexusPixels() method is:
2554%
cristy4c08aed2011-07-01 19:47:50 +00002555% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002556% NexusInfo *nexus_info)
2557%
2558% A description of each parameter follows:
2559%
2560% o cache: the pixel cache.
2561%
2562% o nexus_info: the cache nexus to return the pixels.
2563%
2564*/
cristya6577ff2011-09-02 19:54:26 +00002565MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002566 NexusInfo *nexus_info)
2567{
2568 CacheInfo
2569 *cache_info;
2570
cristy9f027d12011-09-21 01:17:17 +00002571 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002572 cache_info=(CacheInfo *) cache;
2573 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002574 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002575 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002576 return(nexus_info->pixels);
2577}
2578
2579/*
2580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2581% %
2582% %
2583% %
cristy056ba772010-01-02 23:33:54 +00002584+ G e t P i x e l C a c h e P i x e l s %
2585% %
2586% %
2587% %
2588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2589%
2590% GetPixelCachePixels() returns the pixels associated with the specified image.
2591%
2592% The format of the GetPixelCachePixels() method is:
2593%
cristyf84a1932010-01-03 18:00:18 +00002594% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2595% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002596%
2597% A description of each parameter follows:
2598%
2599% o image: the image.
2600%
2601% o length: the pixel cache length.
2602%
cristyf84a1932010-01-03 18:00:18 +00002603% o exception: return any errors or warnings in this structure.
2604%
cristy056ba772010-01-02 23:33:54 +00002605*/
cristyd1dd6e42011-09-04 01:46:08 +00002606MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002607 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002608{
2609 CacheInfo
2610 *cache_info;
2611
2612 assert(image != (const Image *) NULL);
2613 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002614 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002615 assert(length != (MagickSizeType *) NULL);
2616 assert(exception != (ExceptionInfo *) NULL);
2617 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002618 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002619 assert(cache_info->signature == MagickSignature);
2620 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002621 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002622 return((void *) NULL);
2623 *length=cache_info->length;
2624 return((void *) cache_info->pixels);
2625}
2626
2627/*
2628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2629% %
2630% %
2631% %
cristyb32b90a2009-09-07 21:45:48 +00002632+ G e t P i x e l C a c h e S t o r a g e C l a s s %
cristy3ed852e2009-09-05 21:47:34 +00002633% %
2634% %
2635% %
2636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2637%
2638% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2639%
2640% The format of the GetPixelCacheStorageClass() method is:
2641%
2642% ClassType GetPixelCacheStorageClass(Cache cache)
2643%
2644% A description of each parameter follows:
2645%
2646% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2647%
2648% o cache: the pixel cache.
2649%
2650*/
cristya6577ff2011-09-02 19:54:26 +00002651MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002652{
2653 CacheInfo
2654 *cache_info;
2655
2656 assert(cache != (Cache) NULL);
2657 cache_info=(CacheInfo *) cache;
2658 assert(cache_info->signature == MagickSignature);
2659 if (cache_info->debug != MagickFalse)
2660 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2661 cache_info->filename);
2662 return(cache_info->storage_class);
2663}
2664
2665/*
2666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2667% %
2668% %
2669% %
cristyb32b90a2009-09-07 21:45:48 +00002670+ G e t P i x e l C a c h e T i l e S i z e %
2671% %
2672% %
2673% %
2674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675%
2676% GetPixelCacheTileSize() returns the pixel cache tile size.
2677%
2678% The format of the GetPixelCacheTileSize() method is:
2679%
cristybb503372010-05-27 20:51:26 +00002680% void GetPixelCacheTileSize(const Image *image,size_t *width,
2681% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002682%
2683% A description of each parameter follows:
2684%
2685% o image: the image.
2686%
2687% o width: the optimize cache tile width in pixels.
2688%
2689% o height: the optimize cache tile height in pixels.
2690%
2691*/
cristya6577ff2011-09-02 19:54:26 +00002692MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002693 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002694{
cristy4c08aed2011-07-01 19:47:50 +00002695 CacheInfo
2696 *cache_info;
2697
cristyb32b90a2009-09-07 21:45:48 +00002698 assert(image != (Image *) NULL);
2699 assert(image->signature == MagickSignature);
2700 if (image->debug != MagickFalse)
2701 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002702 cache_info=(CacheInfo *) image->cache;
2703 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002704 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristy238287d2012-05-17 18:16:56 +00002705 if (GetImagePixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002706 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002707 *height=(*width);
2708}
2709
2710/*
2711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2712% %
2713% %
2714% %
cristy3ed852e2009-09-05 21:47:34 +00002715+ G e t P i x e l C a c h e V i r t u a l M e t h o d %
2716% %
2717% %
2718% %
2719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2720%
2721% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2722% pixel cache. A virtual pixel is any pixel access that is outside the
2723% boundaries of the image cache.
2724%
2725% The format of the GetPixelCacheVirtualMethod() method is:
2726%
2727% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2728%
2729% A description of each parameter follows:
2730%
2731% o image: the image.
2732%
2733*/
cristyd1dd6e42011-09-04 01:46:08 +00002734MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002735{
2736 CacheInfo
2737 *cache_info;
2738
2739 assert(image != (Image *) NULL);
2740 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002741 assert(image->cache != (Cache) NULL);
2742 cache_info=(CacheInfo *) image->cache;
2743 assert(cache_info->signature == MagickSignature);
2744 return(cache_info->virtual_pixel_method);
2745}
2746
2747/*
2748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749% %
2750% %
2751% %
cristy4c08aed2011-07-01 19:47:50 +00002752+ G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00002753% %
2754% %
2755% %
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757%
cristy4c08aed2011-07-01 19:47:50 +00002758% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2759% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002760%
cristy4c08aed2011-07-01 19:47:50 +00002761% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002762%
cristy4c08aed2011-07-01 19:47:50 +00002763% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002764%
2765% A description of each parameter follows:
2766%
2767% o image: the image.
2768%
2769*/
cristy4c08aed2011-07-01 19:47:50 +00002770static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002771{
2772 CacheInfo
2773 *cache_info;
2774
cristy5c9e6f22010-09-17 17:31:01 +00002775 const int
2776 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002777
cristy4c08aed2011-07-01 19:47:50 +00002778 const void
2779 *metacontent;
2780
cristye7cc7cf2010-09-21 13:26:47 +00002781 assert(image != (const Image *) NULL);
2782 assert(image->signature == MagickSignature);
2783 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002784 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002785 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002786 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002787 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2788 cache_info->nexus_info[id]);
2789 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002790}
2791
2792/*
2793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2794% %
2795% %
2796% %
cristy4c08aed2011-07-01 19:47:50 +00002797+ G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00002798% %
2799% %
2800% %
2801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802%
cristy4c08aed2011-07-01 19:47:50 +00002803% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2804% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002805%
cristy4c08aed2011-07-01 19:47:50 +00002806% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002807%
cristy4c08aed2011-07-01 19:47:50 +00002808% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002809% NexusInfo *nexus_info)
2810%
2811% A description of each parameter follows:
2812%
2813% o cache: the pixel cache.
2814%
cristy4c08aed2011-07-01 19:47:50 +00002815% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002816%
2817*/
cristya6577ff2011-09-02 19:54:26 +00002818MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002819 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002820{
2821 CacheInfo
2822 *cache_info;
2823
cristye7cc7cf2010-09-21 13:26:47 +00002824 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002825 cache_info=(CacheInfo *) cache;
2826 assert(cache_info->signature == MagickSignature);
2827 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002828 return((void *) NULL);
2829 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002830}
2831
2832/*
2833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2834% %
2835% %
2836% %
cristy4c08aed2011-07-01 19:47:50 +00002837% G e t V i r t u a l M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002838% %
2839% %
2840% %
2841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2842%
cristy4c08aed2011-07-01 19:47:50 +00002843% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2844% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2845% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002846%
cristy4c08aed2011-07-01 19:47:50 +00002847% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002848%
cristy4c08aed2011-07-01 19:47:50 +00002849% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002850%
2851% A description of each parameter follows:
2852%
2853% o image: the image.
2854%
2855*/
cristy4c08aed2011-07-01 19:47:50 +00002856MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002857{
2858 CacheInfo
2859 *cache_info;
2860
cristy2036f5c2010-09-19 21:18:17 +00002861 const int
2862 id = GetOpenMPThreadId();
2863
cristy4c08aed2011-07-01 19:47:50 +00002864 const void
2865 *metacontent;
2866
cristy3ed852e2009-09-05 21:47:34 +00002867 assert(image != (const Image *) NULL);
2868 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002869 assert(image->cache != (Cache) NULL);
2870 cache_info=(CacheInfo *) image->cache;
2871 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002872 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002873 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002874 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002875 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002876 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2877 cache_info->nexus_info[id]);
2878 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002879}
2880
2881/*
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883% %
2884% %
2885% %
2886+ G e t V i r t u a l P i x e l s F r o m N e x u s %
2887% %
2888% %
2889% %
2890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891%
2892% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2893% pixel cache as defined by the geometry parameters. A pointer to the pixels
2894% is returned if the pixels are transferred, otherwise a NULL is returned.
2895%
2896% The format of the GetVirtualPixelsFromNexus() method is:
2897%
cristy4c08aed2011-07-01 19:47:50 +00002898% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002899% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002900% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2901% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002902%
2903% A description of each parameter follows:
2904%
2905% o image: the image.
2906%
2907% o virtual_pixel_method: the virtual pixel method.
2908%
2909% o x,y,columns,rows: These values define the perimeter of a region of
2910% pixels.
2911%
2912% o nexus_info: the cache nexus to acquire.
2913%
2914% o exception: return any errors or warnings in this structure.
2915%
2916*/
2917
cristybb503372010-05-27 20:51:26 +00002918static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002919 DitherMatrix[64] =
2920 {
2921 0, 48, 12, 60, 3, 51, 15, 63,
2922 32, 16, 44, 28, 35, 19, 47, 31,
2923 8, 56, 4, 52, 11, 59, 7, 55,
2924 40, 24, 36, 20, 43, 27, 39, 23,
2925 2, 50, 14, 62, 1, 49, 13, 61,
2926 34, 18, 46, 30, 33, 17, 45, 29,
2927 10, 58, 6, 54, 9, 57, 5, 53,
2928 42, 26, 38, 22, 41, 25, 37, 21
2929 };
2930
cristybb503372010-05-27 20:51:26 +00002931static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002932{
cristybb503372010-05-27 20:51:26 +00002933 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002934 index;
2935
2936 index=x+DitherMatrix[x & 0x07]-32L;
2937 if (index < 0L)
2938 return(0L);
cristybb503372010-05-27 20:51:26 +00002939 if (index >= (ssize_t) columns)
2940 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002941 return(index);
2942}
2943
cristybb503372010-05-27 20:51:26 +00002944static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002945{
cristybb503372010-05-27 20:51:26 +00002946 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002947 index;
2948
2949 index=y+DitherMatrix[y & 0x07]-32L;
2950 if (index < 0L)
2951 return(0L);
cristybb503372010-05-27 20:51:26 +00002952 if (index >= (ssize_t) rows)
2953 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002954 return(index);
2955}
2956
cristybb503372010-05-27 20:51:26 +00002957static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002958{
2959 if (x < 0L)
2960 return(0L);
cristybb503372010-05-27 20:51:26 +00002961 if (x >= (ssize_t) columns)
2962 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002963 return(x);
2964}
2965
cristybb503372010-05-27 20:51:26 +00002966static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002967{
2968 if (y < 0L)
2969 return(0L);
cristybb503372010-05-27 20:51:26 +00002970 if (y >= (ssize_t) rows)
2971 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002972 return(y);
2973}
2974
cristybb503372010-05-27 20:51:26 +00002975static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002976{
cristybb503372010-05-27 20:51:26 +00002977 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002978}
2979
cristybb503372010-05-27 20:51:26 +00002980static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002981{
cristybb503372010-05-27 20:51:26 +00002982 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002983}
2984
cristybb503372010-05-27 20:51:26 +00002985static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2986 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002987{
2988 MagickModulo
2989 modulo;
2990
cristy6162bb42011-07-18 11:34:09 +00002991 /*
2992 Compute the remainder of dividing offset by extent. It returns not only
2993 the quotient (tile the offset falls in) but also the positive remainer
2994 within that tile such that 0 <= remainder < extent. This method is
2995 essentially a ldiv() using a floored modulo division rather than the
2996 normal default truncated modulo division.
2997 */
cristybb503372010-05-27 20:51:26 +00002998 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002999 if (offset < 0L)
3000 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003001 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003002 return(modulo);
3003}
3004
cristya6577ff2011-09-02 19:54:26 +00003005MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003006 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3007 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003008 ExceptionInfo *exception)
3009{
3010 CacheInfo
3011 *cache_info;
3012
3013 MagickOffsetType
3014 offset;
3015
3016 MagickSizeType
3017 length,
3018 number_pixels;
3019
3020 NexusInfo
3021 **virtual_nexus;
3022
cristy4c08aed2011-07-01 19:47:50 +00003023 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003024 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003025 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003026
3027 RectangleInfo
3028 region;
3029
cristy4c08aed2011-07-01 19:47:50 +00003030 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003031 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003032
cristy4c08aed2011-07-01 19:47:50 +00003033 register const void
3034 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003035
cristy4c08aed2011-07-01 19:47:50 +00003036 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003037 *restrict q;
3038
cristybb503372010-05-27 20:51:26 +00003039 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003040 i,
3041 u;
cristy3ed852e2009-09-05 21:47:34 +00003042
cristy4c08aed2011-07-01 19:47:50 +00003043 register unsigned char
3044 *restrict s;
3045
cristy105ba3c2011-07-18 02:28:38 +00003046 ssize_t
3047 v;
3048
cristy4c08aed2011-07-01 19:47:50 +00003049 void
cristy105ba3c2011-07-18 02:28:38 +00003050 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003051
cristy3ed852e2009-09-05 21:47:34 +00003052 /*
3053 Acquire pixels.
3054 */
cristye7cc7cf2010-09-21 13:26:47 +00003055 assert(image != (const Image *) NULL);
3056 assert(image->signature == MagickSignature);
3057 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003058 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003059 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003060 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003061 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003062 region.x=x;
3063 region.y=y;
3064 region.width=columns;
3065 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003066 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003067 if (pixels == (Quantum *) NULL)
3068 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003069 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003070 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3071 nexus_info->region.x;
3072 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3073 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003074 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3075 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003076 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3077 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003078 {
3079 MagickBooleanType
3080 status;
3081
3082 /*
3083 Pixel request is inside cache extents.
3084 */
cristy4c08aed2011-07-01 19:47:50 +00003085 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003086 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003087 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3088 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003089 return((const Quantum *) NULL);
3090 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003091 {
cristy4c08aed2011-07-01 19:47:50 +00003092 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003093 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003094 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003095 }
cristyacd2ed22011-08-30 01:44:23 +00003096 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003097 }
3098 /*
3099 Pixel request is outside cache extents.
3100 */
cristy4c08aed2011-07-01 19:47:50 +00003101 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003102 virtual_nexus=AcquirePixelCacheNexus(1);
3103 if (virtual_nexus == (NexusInfo **) NULL)
3104 {
cristy4c08aed2011-07-01 19:47:50 +00003105 if (virtual_nexus != (NexusInfo **) NULL)
3106 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003107 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003108 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003109 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003110 }
cristy105ba3c2011-07-18 02:28:38 +00003111 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3112 sizeof(*virtual_pixel));
3113 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003114 switch (virtual_pixel_method)
3115 {
cristy4c08aed2011-07-01 19:47:50 +00003116 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003117 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003118 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003119 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 case MaskVirtualPixelMethod:
3121 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003122 case EdgeVirtualPixelMethod:
3123 case CheckerTileVirtualPixelMethod:
3124 case HorizontalTileVirtualPixelMethod:
3125 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003126 {
cristy4c08aed2011-07-01 19:47:50 +00003127 if (cache_info->metacontent_extent != 0)
3128 {
cristy6162bb42011-07-18 11:34:09 +00003129 /*
3130 Acquire a metacontent buffer.
3131 */
cristya64b85d2011-09-14 01:02:31 +00003132 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003133 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003134 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003135 {
cristy4c08aed2011-07-01 19:47:50 +00003136 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3137 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003138 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003139 return((const Quantum *) NULL);
3140 }
cristy105ba3c2011-07-18 02:28:38 +00003141 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003142 cache_info->metacontent_extent);
3143 }
3144 switch (virtual_pixel_method)
3145 {
3146 case BlackVirtualPixelMethod:
3147 {
cristy30301712011-07-18 15:06:51 +00003148 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3149 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003150 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3151 break;
3152 }
3153 case GrayVirtualPixelMethod:
3154 {
cristy30301712011-07-18 15:06:51 +00003155 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003156 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3157 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003158 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3159 break;
3160 }
3161 case TransparentVirtualPixelMethod:
3162 {
cristy30301712011-07-18 15:06:51 +00003163 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3164 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003165 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3166 break;
3167 }
3168 case MaskVirtualPixelMethod:
3169 case WhiteVirtualPixelMethod:
3170 {
cristy30301712011-07-18 15:06:51 +00003171 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3172 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003173 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3174 break;
3175 }
3176 default:
3177 {
cristy9e0719b2011-12-29 03:45:45 +00003178 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3179 virtual_pixel);
3180 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3181 virtual_pixel);
3182 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3183 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003184 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3185 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003186 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3187 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003188 break;
3189 }
3190 }
cristy3ed852e2009-09-05 21:47:34 +00003191 break;
3192 }
3193 default:
cristy3ed852e2009-09-05 21:47:34 +00003194 break;
cristy3ed852e2009-09-05 21:47:34 +00003195 }
cristybb503372010-05-27 20:51:26 +00003196 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003197 {
cristybb503372010-05-27 20:51:26 +00003198 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003199 {
3200 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003201 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003202 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3203 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003204 {
3205 MagickModulo
3206 x_modulo,
3207 y_modulo;
3208
3209 /*
3210 Transfer a single pixel.
3211 */
3212 length=(MagickSizeType) 1;
3213 switch (virtual_pixel_method)
3214 {
cristy3ed852e2009-09-05 21:47:34 +00003215 default:
3216 {
3217 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003218 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003219 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003220 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003221 break;
3222 }
3223 case RandomVirtualPixelMethod:
3224 {
3225 if (cache_info->random_info == (RandomInfo *) NULL)
3226 cache_info->random_info=AcquireRandomInfo();
3227 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003228 RandomX(cache_info->random_info,cache_info->columns),
3229 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003230 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003231 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003232 break;
3233 }
3234 case DitherVirtualPixelMethod:
3235 {
3236 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003237 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003238 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003239 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003240 break;
3241 }
3242 case TileVirtualPixelMethod:
3243 {
3244 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3245 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3246 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003247 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003248 exception);
cristy4c08aed2011-07-01 19:47:50 +00003249 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003250 break;
3251 }
3252 case MirrorVirtualPixelMethod:
3253 {
3254 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3255 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003256 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003257 x_modulo.remainder-1L;
3258 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3259 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003260 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003261 y_modulo.remainder-1L;
3262 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003263 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003264 exception);
cristy4c08aed2011-07-01 19:47:50 +00003265 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003266 break;
3267 }
3268 case HorizontalTileEdgeVirtualPixelMethod:
3269 {
3270 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3271 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003272 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003273 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003274 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003275 break;
3276 }
3277 case VerticalTileEdgeVirtualPixelMethod:
3278 {
3279 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3280 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003281 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003282 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003283 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3284 break;
3285 }
3286 case BackgroundVirtualPixelMethod:
3287 case BlackVirtualPixelMethod:
3288 case GrayVirtualPixelMethod:
3289 case TransparentVirtualPixelMethod:
3290 case MaskVirtualPixelMethod:
3291 case WhiteVirtualPixelMethod:
3292 {
3293 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003294 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003295 break;
3296 }
3297 case EdgeVirtualPixelMethod:
3298 case CheckerTileVirtualPixelMethod:
3299 {
3300 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3301 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3302 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3303 {
3304 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003305 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003306 break;
3307 }
3308 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3309 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3310 exception);
3311 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3312 break;
3313 }
3314 case HorizontalTileVirtualPixelMethod:
3315 {
3316 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3317 {
3318 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003319 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003320 break;
3321 }
3322 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3323 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3324 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3325 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3326 exception);
3327 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3328 break;
3329 }
3330 case VerticalTileVirtualPixelMethod:
3331 {
3332 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3333 {
3334 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003335 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003336 break;
3337 }
3338 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3339 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3340 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3341 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3342 exception);
3343 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003344 break;
3345 }
3346 }
cristy4c08aed2011-07-01 19:47:50 +00003347 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003348 break;
cristyed231572011-07-14 02:18:59 +00003349 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003350 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003351 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003352 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003353 {
3354 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3355 s+=cache_info->metacontent_extent;
3356 }
cristy3ed852e2009-09-05 21:47:34 +00003357 continue;
3358 }
3359 /*
3360 Transfer a run of pixels.
3361 */
cristy4c08aed2011-07-01 19:47:50 +00003362 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3363 length,1UL,*virtual_nexus,exception);
3364 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003365 break;
cristy4c08aed2011-07-01 19:47:50 +00003366 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003367 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3368 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003369 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003370 {
cristy4c08aed2011-07-01 19:47:50 +00003371 (void) memcpy(s,r,(size_t) length);
3372 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003373 }
3374 }
3375 }
cristy4c08aed2011-07-01 19:47:50 +00003376 /*
3377 Free resources.
3378 */
cristy105ba3c2011-07-18 02:28:38 +00003379 if (virtual_metacontent != (void *) NULL)
3380 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003381 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3382 return(pixels);
3383}
3384
3385/*
3386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3387% %
3388% %
3389% %
3390+ G e t V i r t u a l P i x e l C a c h e %
3391% %
3392% %
3393% %
3394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3395%
3396% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3397% cache as defined by the geometry parameters. A pointer to the pixels
3398% is returned if the pixels are transferred, otherwise a NULL is returned.
3399%
3400% The format of the GetVirtualPixelCache() method is:
3401%
cristy4c08aed2011-07-01 19:47:50 +00003402% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003403% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3404% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003405% ExceptionInfo *exception)
3406%
3407% A description of each parameter follows:
3408%
3409% o image: the image.
3410%
3411% o virtual_pixel_method: the virtual pixel method.
3412%
3413% o x,y,columns,rows: These values define the perimeter of a region of
3414% pixels.
3415%
3416% o exception: return any errors or warnings in this structure.
3417%
3418*/
cristy4c08aed2011-07-01 19:47:50 +00003419static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003420 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3421 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003422{
3423 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003424 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003425
cristy5c9e6f22010-09-17 17:31:01 +00003426 const int
3427 id = GetOpenMPThreadId();
3428
cristy4c08aed2011-07-01 19:47:50 +00003429 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003430 *p;
cristy4c08aed2011-07-01 19:47:50 +00003431
cristye7cc7cf2010-09-21 13:26:47 +00003432 assert(image != (const Image *) NULL);
3433 assert(image->signature == MagickSignature);
3434 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003435 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003436 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003437 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003439 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003440 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003441}
3442
3443/*
3444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3445% %
3446% %
3447% %
3448% G e t V i r t u a l P i x e l Q u e u e %
3449% %
3450% %
3451% %
3452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3453%
cristy4c08aed2011-07-01 19:47:50 +00003454% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3455% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003456%
3457% The format of the GetVirtualPixelQueue() method is:
3458%
cristy4c08aed2011-07-01 19:47:50 +00003459% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003460%
3461% A description of each parameter follows:
3462%
3463% o image: the image.
3464%
3465*/
cristy4c08aed2011-07-01 19:47:50 +00003466MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003467{
3468 CacheInfo
3469 *cache_info;
3470
cristy2036f5c2010-09-19 21:18:17 +00003471 const int
3472 id = GetOpenMPThreadId();
3473
cristy3ed852e2009-09-05 21:47:34 +00003474 assert(image != (const Image *) NULL);
3475 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003476 assert(image->cache != (Cache) NULL);
3477 cache_info=(CacheInfo *) image->cache;
3478 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003479 if (cache_info->methods.get_virtual_pixels_handler !=
3480 (GetVirtualPixelsHandler) NULL)
3481 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003482 assert(id < (int) cache_info->number_threads);
3483 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003484}
3485
3486/*
3487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3488% %
3489% %
3490% %
3491% G e t V i r t u a l P i x e l s %
3492% %
3493% %
3494% %
3495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3496%
3497% GetVirtualPixels() returns an immutable pixel region. If the
3498% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003499% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003500% copy of the pixels or it may point to the original pixels in memory.
3501% Performance is maximized if the selected region is part of one row, or one
3502% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003503% (without a copy) if the image is in memory, or in a memory-mapped file. The
3504% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003505%
3506% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003507% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3508% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3509% access the meta-content (of type void) corresponding to the the
3510% region.
cristy3ed852e2009-09-05 21:47:34 +00003511%
3512% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3513%
3514% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3515% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3516% GetCacheViewAuthenticPixels() instead.
3517%
3518% The format of the GetVirtualPixels() method is:
3519%
cristy4c08aed2011-07-01 19:47:50 +00003520% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003521% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003522% ExceptionInfo *exception)
3523%
3524% A description of each parameter follows:
3525%
3526% o image: the image.
3527%
3528% o x,y,columns,rows: These values define the perimeter of a region of
3529% pixels.
3530%
3531% o exception: return any errors or warnings in this structure.
3532%
3533*/
cristy4c08aed2011-07-01 19:47:50 +00003534MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003535 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3536 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003537{
3538 CacheInfo
3539 *cache_info;
3540
cristy2036f5c2010-09-19 21:18:17 +00003541 const int
3542 id = GetOpenMPThreadId();
3543
cristy4c08aed2011-07-01 19:47:50 +00003544 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003545 *p;
cristy4c08aed2011-07-01 19:47:50 +00003546
cristy3ed852e2009-09-05 21:47:34 +00003547 assert(image != (const Image *) NULL);
3548 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003549 assert(image->cache != (Cache) NULL);
3550 cache_info=(CacheInfo *) image->cache;
3551 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003552 if (cache_info->methods.get_virtual_pixel_handler !=
3553 (GetVirtualPixelHandler) NULL)
3554 return(cache_info->methods.get_virtual_pixel_handler(image,
3555 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003556 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003557 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003558 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003559 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003560}
3561
3562/*
3563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3564% %
3565% %
3566% %
3567+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3568% %
3569% %
3570% %
3571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3572%
cristy4c08aed2011-07-01 19:47:50 +00003573% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3574% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003575%
3576% The format of the GetVirtualPixelsCache() method is:
3577%
cristy4c08aed2011-07-01 19:47:50 +00003578% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003579%
3580% A description of each parameter follows:
3581%
3582% o image: the image.
3583%
3584*/
cristy4c08aed2011-07-01 19:47:50 +00003585static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003586{
3587 CacheInfo
3588 *cache_info;
3589
cristy5c9e6f22010-09-17 17:31:01 +00003590 const int
3591 id = GetOpenMPThreadId();
3592
cristye7cc7cf2010-09-21 13:26:47 +00003593 assert(image != (const Image *) NULL);
3594 assert(image->signature == MagickSignature);
3595 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003596 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003597 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003598 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003599 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003600}
3601
3602/*
3603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604% %
3605% %
3606% %
3607+ G e t V i r t u a l P i x e l s N e x u s %
3608% %
3609% %
3610% %
3611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3612%
3613% GetVirtualPixelsNexus() returns the pixels associated with the specified
3614% cache nexus.
3615%
3616% The format of the GetVirtualPixelsNexus() method is:
3617%
cristy4c08aed2011-07-01 19:47:50 +00003618% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003619% NexusInfo *nexus_info)
3620%
3621% A description of each parameter follows:
3622%
3623% o cache: the pixel cache.
3624%
3625% o nexus_info: the cache nexus to return the colormap pixels.
3626%
3627*/
cristya6577ff2011-09-02 19:54:26 +00003628MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003629 NexusInfo *nexus_info)
3630{
3631 CacheInfo
3632 *cache_info;
3633
cristye7cc7cf2010-09-21 13:26:47 +00003634 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003635 cache_info=(CacheInfo *) cache;
3636 assert(cache_info->signature == MagickSignature);
3637 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003638 return((Quantum *) NULL);
3639 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003640}
3641
3642/*
3643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3644% %
3645% %
3646% %
cristy3ed852e2009-09-05 21:47:34 +00003647+ O p e n P i x e l C a c h e %
3648% %
3649% %
3650% %
3651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3652%
3653% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3654% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003655% metacontent, and memory mapping the cache if it is disk based. The cache
3656% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003657%
3658% The format of the OpenPixelCache() method is:
3659%
3660% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3661% ExceptionInfo *exception)
3662%
3663% A description of each parameter follows:
3664%
3665% o image: the image.
3666%
3667% o mode: ReadMode, WriteMode, or IOMode.
3668%
3669% o exception: return any errors or warnings in this structure.
3670%
3671*/
3672
cristyd43a46b2010-01-21 02:13:41 +00003673static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003674{
3675 cache_info->mapped=MagickFalse;
cristye42639a2012-08-23 01:53:24 +00003676 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3677 (size_t) cache_info->length));
cristy4c08aed2011-07-01 19:47:50 +00003678 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003679 {
3680 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003681 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003682 cache_info->length);
3683 }
3684}
3685
3686static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3687{
3688 CacheInfo
3689 *cache_info;
3690
3691 MagickOffsetType
cristy3ed852e2009-09-05 21:47:34 +00003692 extent,
3693 offset;
3694
3695 cache_info=(CacheInfo *) image->cache;
3696 if (image->debug != MagickFalse)
3697 {
3698 char
3699 format[MaxTextExtent],
3700 message[MaxTextExtent];
3701
cristyb9080c92009-12-01 20:13:26 +00003702 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003703 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003704 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003705 cache_info->cache_filename,cache_info->file,format);
3706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3707 }
3708 if (length != (MagickSizeType) ((MagickOffsetType) length))
3709 return(MagickFalse);
cristy911f2b12012-10-18 14:55:28 +00003710 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3711 if (offset < 0)
cristy3ed852e2009-09-05 21:47:34 +00003712 return(MagickFalse);
cristy911f2b12012-10-18 14:55:28 +00003713 if ((MagickSizeType) offset >= length)
cristy3ed852e2009-09-05 21:47:34 +00003714 return(MagickTrue);
cristy911f2b12012-10-18 14:55:28 +00003715 extent=(MagickOffsetType) length-1;
cristy3b5a2cf2012-10-18 14:50:08 +00003716#if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3717 {
3718 MagickOffsetType
3719 count;
3720
cristy911f2b12012-10-18 14:55:28 +00003721 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
cristy3b5a2cf2012-10-18 14:50:08 +00003722 if (count != (MagickOffsetType) 1)
3723 return(MagickFalse);
3724 }
3725#else
3726 {
3727 int
3728 status;
3729
cristy911f2b12012-10-18 14:55:28 +00003730 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
cristy3b5a2cf2012-10-18 14:50:08 +00003731 if (status != 0)
3732 return(MagickFalse);
3733 }
3734#endif
3735 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003736}
3737
3738static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3739 ExceptionInfo *exception)
3740{
cristy3ed852e2009-09-05 21:47:34 +00003741 CacheInfo
3742 *cache_info,
3743 source_info;
3744
cristyf3a6a9d2010-11-07 21:02:56 +00003745 char
3746 format[MaxTextExtent],
3747 message[MaxTextExtent];
3748
cristy4c08aed2011-07-01 19:47:50 +00003749 MagickBooleanType
3750 status;
3751
cristy3ed852e2009-09-05 21:47:34 +00003752 MagickSizeType
3753 length,
3754 number_pixels;
3755
cristy3ed852e2009-09-05 21:47:34 +00003756 size_t
cristye076a6e2010-08-15 19:59:43 +00003757 columns,
cristy3ed852e2009-09-05 21:47:34 +00003758 packet_size;
3759
cristye7cc7cf2010-09-21 13:26:47 +00003760 assert(image != (const Image *) NULL);
3761 assert(image->signature == MagickSignature);
3762 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003763 if (image->debug != MagickFalse)
3764 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3765 if ((image->columns == 0) || (image->rows == 0))
3766 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3767 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003768 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003769 source_info=(*cache_info);
3770 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003771 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003772 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003773 cache_info->storage_class=image->storage_class;
3774 cache_info->colorspace=image->colorspace;
cristy8a46d822012-08-28 23:32:39 +00003775 cache_info->alpha_trait=image->alpha_trait;
cristy183a5c72012-01-30 01:40:35 +00003776 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003777 cache_info->rows=image->rows;
3778 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003779 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003780 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003781 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3782 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003783 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003784 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003785 if (image->ping != MagickFalse)
3786 {
cristy73724512010-04-12 14:43:14 +00003787 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003788 cache_info->pixels=(Quantum *) NULL;
3789 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003790 cache_info->length=0;
3791 return(MagickTrue);
3792 }
cristy3ed852e2009-09-05 21:47:34 +00003793 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003794 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003795 if (image->metacontent_extent != 0)
3796 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003797 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003798 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003799 if (cache_info->columns != columns)
3800 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3801 image->filename);
3802 cache_info->length=length;
3803 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003804 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003805 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003806 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3807 {
3808 status=AcquireMagickResource(MemoryResource,cache_info->length);
3809 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3810 (cache_info->type == MemoryCache))
3811 {
cristyd43a46b2010-01-21 02:13:41 +00003812 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003813 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003814 cache_info->pixels=source_info.pixels;
3815 else
3816 {
3817 /*
3818 Create memory pixel cache.
3819 */
cristy4c08aed2011-07-01 19:47:50 +00003820 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003821 if (image->debug != MagickFalse)
3822 {
cristy32cacff2011-12-31 03:36:27 +00003823 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003824 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003825 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3826 cache_info->filename,cache_info->mapped != MagickFalse ?
3827 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003828 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003829 format);
cristy3ed852e2009-09-05 21:47:34 +00003830 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3831 message);
3832 }
cristy3ed852e2009-09-05 21:47:34 +00003833 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003834 cache_info->metacontent=(void *) NULL;
3835 if (cache_info->metacontent_extent != 0)
3836 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003837 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003838 if ((source_info.storage_class != UndefinedClass) &&
3839 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003840 {
cristy4c08aed2011-07-01 19:47:50 +00003841 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003842 exception);
3843 RelinquishPixelCachePixels(&source_info);
3844 }
cristy4c08aed2011-07-01 19:47:50 +00003845 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003846 }
3847 }
3848 RelinquishMagickResource(MemoryResource,cache_info->length);
3849 }
3850 /*
3851 Create pixel cache on disk.
3852 */
3853 status=AcquireMagickResource(DiskResource,cache_info->length);
3854 if (status == MagickFalse)
3855 {
3856 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003857 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003858 return(MagickFalse);
3859 }
cristy413f1302012-01-01 17:48:27 +00003860 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3861 {
3862 (void) ClosePixelCacheOnDisk(cache_info);
3863 *cache_info->cache_filename='\0';
3864 }
cristy3ed852e2009-09-05 21:47:34 +00003865 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3866 {
3867 RelinquishMagickResource(DiskResource,cache_info->length);
3868 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3869 image->filename);
3870 return(MagickFalse);
3871 }
3872 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3873 cache_info->length);
3874 if (status == MagickFalse)
3875 {
3876 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3877 image->filename);
3878 return(MagickFalse);
3879 }
cristyed231572011-07-14 02:18:59 +00003880 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003881 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003882 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003883 cache_info->type=DiskCache;
3884 else
3885 {
3886 status=AcquireMagickResource(MapResource,cache_info->length);
3887 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3888 (cache_info->type != MemoryCache))
3889 cache_info->type=DiskCache;
3890 else
3891 {
cristy4c08aed2011-07-01 19:47:50 +00003892 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003893 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003894 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003895 {
cristy3ed852e2009-09-05 21:47:34 +00003896 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003897 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003898 }
3899 else
3900 {
3901 /*
3902 Create file-backed memory-mapped pixel cache.
3903 */
cristy4c08aed2011-07-01 19:47:50 +00003904 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003905 (void) ClosePixelCacheOnDisk(cache_info);
3906 cache_info->type=MapCache;
3907 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003908 cache_info->metacontent=(void *) NULL;
3909 if (cache_info->metacontent_extent != 0)
3910 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003911 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003912 if ((source_info.storage_class != UndefinedClass) &&
3913 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003914 {
3915 status=ClonePixelCachePixels(cache_info,&source_info,
3916 exception);
3917 RelinquishPixelCachePixels(&source_info);
3918 }
3919 if (image->debug != MagickFalse)
3920 {
cristy413f1302012-01-01 17:48:27 +00003921 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003922 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003923 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003924 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003925 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003926 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003927 format);
cristy3ed852e2009-09-05 21:47:34 +00003928 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3929 message);
3930 }
cristy4c08aed2011-07-01 19:47:50 +00003931 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003932 }
3933 }
3934 RelinquishMagickResource(MapResource,cache_info->length);
3935 }
cristy4c08aed2011-07-01 19:47:50 +00003936 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003937 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003938 {
3939 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3940 RelinquishPixelCachePixels(&source_info);
3941 }
3942 if (image->debug != MagickFalse)
3943 {
cristyb9080c92009-12-01 20:13:26 +00003944 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003945 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003946 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003947 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003948 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003949 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003950 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3951 }
cristy4c08aed2011-07-01 19:47:50 +00003952 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003953}
3954
3955/*
3956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3957% %
3958% %
3959% %
3960+ P e r s i s t P i x e l C a c h e %
3961% %
3962% %
3963% %
3964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3965%
3966% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3967% persistent pixel cache is one that resides on disk and is not destroyed
3968% when the program exits.
3969%
3970% The format of the PersistPixelCache() method is:
3971%
3972% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3973% const MagickBooleanType attach,MagickOffsetType *offset,
3974% ExceptionInfo *exception)
3975%
3976% A description of each parameter follows:
3977%
3978% o image: the image.
3979%
3980% o filename: the persistent pixel cache filename.
3981%
cristyf3a6a9d2010-11-07 21:02:56 +00003982% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003983%
cristy3ed852e2009-09-05 21:47:34 +00003984% o initialize: A value other than zero initializes the persistent pixel
3985% cache.
3986%
3987% o offset: the offset in the persistent cache to store pixels.
3988%
3989% o exception: return any errors or warnings in this structure.
3990%
3991*/
3992MagickExport MagickBooleanType PersistPixelCache(Image *image,
3993 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3994 ExceptionInfo *exception)
3995{
3996 CacheInfo
3997 *cache_info,
3998 *clone_info;
3999
4000 Image
4001 clone_image;
4002
cristy3ed852e2009-09-05 21:47:34 +00004003 MagickBooleanType
4004 status;
4005
cristye076a6e2010-08-15 19:59:43 +00004006 ssize_t
4007 page_size;
4008
cristy3ed852e2009-09-05 21:47:34 +00004009 assert(image != (Image *) NULL);
4010 assert(image->signature == MagickSignature);
4011 if (image->debug != MagickFalse)
4012 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4013 assert(image->cache != (void *) NULL);
4014 assert(filename != (const char *) NULL);
4015 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004016 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004017 cache_info=(CacheInfo *) image->cache;
4018 assert(cache_info->signature == MagickSignature);
4019 if (attach != MagickFalse)
4020 {
4021 /*
cristy01b7eb02009-09-10 23:10:14 +00004022 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004023 */
4024 if (image->debug != MagickFalse)
4025 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004026 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004027 (void) CopyMagickString(cache_info->cache_filename,filename,
4028 MaxTextExtent);
4029 cache_info->type=DiskCache;
4030 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004031 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004032 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004033 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004034 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004035 }
cristy01b7eb02009-09-10 23:10:14 +00004036 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4037 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004038 {
cristyf84a1932010-01-03 18:00:18 +00004039 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004040 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004041 (cache_info->reference_count == 1))
4042 {
4043 int
4044 status;
4045
4046 /*
cristy01b7eb02009-09-10 23:10:14 +00004047 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004048 */
cristy320684d2011-09-23 14:55:47 +00004049 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004050 if (status == 0)
4051 {
4052 (void) CopyMagickString(cache_info->cache_filename,filename,
4053 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004054 *offset+=cache_info->length+page_size-(cache_info->length %
4055 page_size);
cristyf84a1932010-01-03 18:00:18 +00004056 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004057 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004058 if (image->debug != MagickFalse)
4059 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4060 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004061 return(MagickTrue);
4062 }
4063 }
cristyf84a1932010-01-03 18:00:18 +00004064 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004065 }
4066 /*
cristy01b7eb02009-09-10 23:10:14 +00004067 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004068 */
4069 clone_image=(*image);
4070 clone_info=(CacheInfo *) clone_image.cache;
4071 image->cache=ClonePixelCache(cache_info);
4072 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4073 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4074 cache_info->type=DiskCache;
4075 cache_info->offset=(*offset);
4076 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004077 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004078 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004079 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004080 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004081 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4082 return(status);
4083}
4084
4085/*
4086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4087% %
4088% %
4089% %
cristyc11dace2012-01-24 16:39:46 +00004090+ 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 +00004091% %
4092% %
4093% %
4094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4095%
cristyc11dace2012-01-24 16:39:46 +00004096% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4097% defined by the region rectangle and returns a pointer to the region. This
4098% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004099% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4100% pixels are transferred, otherwise a NULL is returned.
4101%
cristyc11dace2012-01-24 16:39:46 +00004102% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004103%
cristyc11dace2012-01-24 16:39:46 +00004104% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004105% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004106% const MagickBooleanType clone,NexusInfo *nexus_info,
4107% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004108%
4109% A description of each parameter follows:
4110%
4111% o image: the image.
4112%
4113% o x,y,columns,rows: These values define the perimeter of a region of
4114% pixels.
4115%
4116% o nexus_info: the cache nexus to set.
4117%
cristy65dbf172011-10-06 17:32:04 +00004118% o clone: clone the pixel cache.
4119%
cristy3ed852e2009-09-05 21:47:34 +00004120% o exception: return any errors or warnings in this structure.
4121%
4122*/
cristyc11dace2012-01-24 16:39:46 +00004123MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4124 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004125 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004126{
4127 CacheInfo
4128 *cache_info;
4129
4130 MagickOffsetType
4131 offset;
4132
4133 MagickSizeType
4134 number_pixels;
4135
4136 RectangleInfo
4137 region;
4138
4139 /*
4140 Validate pixel cache geometry.
4141 */
cristye7cc7cf2010-09-21 13:26:47 +00004142 assert(image != (const Image *) NULL);
4143 assert(image->signature == MagickSignature);
4144 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004145 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004146 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004147 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004148 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004149 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4150 {
4151 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004152 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004153 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004154 }
cristybb503372010-05-27 20:51:26 +00004155 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4156 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004157 {
4158 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004159 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004160 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004161 }
4162 offset=(MagickOffsetType) y*cache_info->columns+x;
4163 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004164 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004165 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4166 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4167 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004168 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004169 /*
4170 Return pixel cache.
4171 */
4172 region.x=x;
4173 region.y=y;
4174 region.width=columns;
4175 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004176 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004177}
4178
4179/*
4180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4181% %
4182% %
4183% %
4184+ 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 %
4185% %
4186% %
4187% %
4188%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4189%
4190% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4191% defined by the region rectangle and returns a pointer to the region. This
4192% region is subsequently transferred from the pixel cache with
4193% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4194% pixels are transferred, otherwise a NULL is returned.
4195%
4196% The format of the QueueAuthenticPixelsCache() method is:
4197%
cristy4c08aed2011-07-01 19:47:50 +00004198% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004199% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004200% ExceptionInfo *exception)
4201%
4202% A description of each parameter follows:
4203%
4204% o image: the image.
4205%
4206% o x,y,columns,rows: These values define the perimeter of a region of
4207% pixels.
4208%
4209% o exception: return any errors or warnings in this structure.
4210%
4211*/
cristy4c08aed2011-07-01 19:47:50 +00004212static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004213 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004214 ExceptionInfo *exception)
4215{
4216 CacheInfo
4217 *cache_info;
4218
cristy5c9e6f22010-09-17 17:31:01 +00004219 const int
4220 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004221
cristy4c08aed2011-07-01 19:47:50 +00004222 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004223 *q;
cristy4c08aed2011-07-01 19:47:50 +00004224
cristye7cc7cf2010-09-21 13:26:47 +00004225 assert(image != (const Image *) NULL);
4226 assert(image->signature == MagickSignature);
4227 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004228 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004229 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004230 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004231 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004232 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004233 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004234}
4235
4236/*
4237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4238% %
4239% %
4240% %
4241% Q u e u e A u t h e n t i c P i x e l s %
4242% %
4243% %
4244% %
4245%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4246%
4247% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004248% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004249% region is returned, otherwise NULL is returned. The returned pointer may
4250% point to a temporary working buffer for the pixels or it may point to the
4251% final location of the pixels in memory.
4252%
4253% Write-only access means that any existing pixel values corresponding to
4254% the region are ignored. This is useful if the initial image is being
4255% created from scratch, or if the existing pixel values are to be
4256% completely replaced without need to refer to their pre-existing values.
4257% The application is free to read and write the pixel buffer returned by
4258% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4259% initialize the pixel array values. Initializing pixel array values is the
4260% application's responsibility.
4261%
4262% Performance is maximized if the selected region is part of one row, or
4263% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004264% pixels in-place (without a copy) if the image is in memory, or in a
4265% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004266% by the user.
4267%
4268% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004269% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4270% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4271% obtain the meta-content (of type void) corresponding to the region.
4272% Once the Quantum (and/or Quantum) array has been updated, the
4273% changes must be saved back to the underlying image using
4274% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004275%
4276% The format of the QueueAuthenticPixels() method is:
4277%
cristy4c08aed2011-07-01 19:47:50 +00004278% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004279% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004280% ExceptionInfo *exception)
4281%
4282% A description of each parameter follows:
4283%
4284% o image: the image.
4285%
4286% o x,y,columns,rows: These values define the perimeter of a region of
4287% pixels.
4288%
4289% o exception: return any errors or warnings in this structure.
4290%
4291*/
cristy4c08aed2011-07-01 19:47:50 +00004292MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004293 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004294 ExceptionInfo *exception)
4295{
4296 CacheInfo
4297 *cache_info;
4298
cristy2036f5c2010-09-19 21:18:17 +00004299 const int
4300 id = GetOpenMPThreadId();
4301
cristy4c08aed2011-07-01 19:47:50 +00004302 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004303 *q;
cristy4c08aed2011-07-01 19:47:50 +00004304
cristy3ed852e2009-09-05 21:47:34 +00004305 assert(image != (Image *) NULL);
4306 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004307 assert(image->cache != (Cache) NULL);
4308 cache_info=(CacheInfo *) image->cache;
4309 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004310 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004311 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004312 {
cristyc36c8822012-02-14 14:02:36 +00004313 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4314 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004315 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004316 }
cristy2036f5c2010-09-19 21:18:17 +00004317 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004318 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004319 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004320 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004321}
4322
4323/*
4324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4325% %
4326% %
4327% %
cristy4c08aed2011-07-01 19:47:50 +00004328+ 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 +00004329% %
4330% %
4331% %
4332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4333%
cristy4c08aed2011-07-01 19:47:50 +00004334% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004335% the pixel cache.
4336%
cristy4c08aed2011-07-01 19:47:50 +00004337% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004338%
cristy4c08aed2011-07-01 19:47:50 +00004339% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004340% NexusInfo *nexus_info,ExceptionInfo *exception)
4341%
4342% A description of each parameter follows:
4343%
4344% o cache_info: the pixel cache.
4345%
cristy4c08aed2011-07-01 19:47:50 +00004346% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004347%
4348% o exception: return any errors or warnings in this structure.
4349%
4350*/
cristy4c08aed2011-07-01 19:47:50 +00004351static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004352 NexusInfo *nexus_info,ExceptionInfo *exception)
4353{
4354 MagickOffsetType
4355 count,
4356 offset;
4357
4358 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004359 extent,
4360 length;
cristy3ed852e2009-09-05 21:47:34 +00004361
cristybb503372010-05-27 20:51:26 +00004362 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004363 y;
4364
cristy4c08aed2011-07-01 19:47:50 +00004365 register unsigned char
4366 *restrict q;
4367
cristybb503372010-05-27 20:51:26 +00004368 size_t
cristy3ed852e2009-09-05 21:47:34 +00004369 rows;
4370
cristy4c08aed2011-07-01 19:47:50 +00004371 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004372 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004373 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004374 return(MagickTrue);
4375 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4376 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004377 length=(MagickSizeType) nexus_info->region.width*
4378 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004379 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004380 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004381 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004382 switch (cache_info->type)
4383 {
4384 case MemoryCache:
4385 case MapCache:
4386 {
cristy4c08aed2011-07-01 19:47:50 +00004387 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004388 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004389
4390 /*
cristy4c08aed2011-07-01 19:47:50 +00004391 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004392 */
cristydd341db2010-03-04 19:06:38 +00004393 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004394 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004395 {
cristy48078b12010-09-23 17:11:01 +00004396 length=extent;
cristydd341db2010-03-04 19:06:38 +00004397 rows=1UL;
4398 }
cristy4c08aed2011-07-01 19:47:50 +00004399 p=(unsigned char *) cache_info->metacontent+offset*
4400 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004401 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004402 {
cristy8f036fe2010-09-18 02:02:00 +00004403 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004404 p+=cache_info->metacontent_extent*cache_info->columns;
4405 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004406 }
4407 break;
4408 }
4409 case DiskCache:
4410 {
4411 /*
cristy4c08aed2011-07-01 19:47:50 +00004412 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004413 */
4414 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4415 {
4416 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4417 cache_info->cache_filename);
4418 return(MagickFalse);
4419 }
cristydd341db2010-03-04 19:06:38 +00004420 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004421 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004422 {
cristy48078b12010-09-23 17:11:01 +00004423 length=extent;
cristydd341db2010-03-04 19:06:38 +00004424 rows=1UL;
4425 }
cristy48078b12010-09-23 17:11:01 +00004426 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004427 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004428 {
cristy48078b12010-09-23 17:11:01 +00004429 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004430 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004431 cache_info->metacontent_extent,length,(unsigned char *) q);
4432 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004433 break;
4434 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004435 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004436 }
cristyc11dace2012-01-24 16:39:46 +00004437 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4438 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004439 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004440 {
4441 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4442 cache_info->cache_filename);
4443 return(MagickFalse);
4444 }
4445 break;
4446 }
4447 default:
4448 break;
4449 }
4450 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004451 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004452 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004453 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004454 nexus_info->region.width,(double) nexus_info->region.height,(double)
4455 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004456 return(MagickTrue);
4457}
4458
4459/*
4460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4461% %
4462% %
4463% %
4464+ R e a d P i x e l C a c h e P i x e l s %
4465% %
4466% %
4467% %
4468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4469%
4470% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4471% cache.
4472%
4473% The format of the ReadPixelCachePixels() method is:
4474%
4475% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4476% NexusInfo *nexus_info,ExceptionInfo *exception)
4477%
4478% A description of each parameter follows:
4479%
4480% o cache_info: the pixel cache.
4481%
4482% o nexus_info: the cache nexus to read the pixels.
4483%
4484% o exception: return any errors or warnings in this structure.
4485%
4486*/
4487static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4488 NexusInfo *nexus_info,ExceptionInfo *exception)
4489{
4490 MagickOffsetType
4491 count,
4492 offset;
4493
4494 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004495 extent,
4496 length;
cristy3ed852e2009-09-05 21:47:34 +00004497
cristy4c08aed2011-07-01 19:47:50 +00004498 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004499 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004500
cristye076a6e2010-08-15 19:59:43 +00004501 register ssize_t
4502 y;
4503
cristybb503372010-05-27 20:51:26 +00004504 size_t
cristy3ed852e2009-09-05 21:47:34 +00004505 rows;
4506
cristy4c08aed2011-07-01 19:47:50 +00004507 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004508 return(MagickTrue);
4509 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4510 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004511 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004512 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004513 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004514 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004515 q=nexus_info->pixels;
4516 switch (cache_info->type)
4517 {
4518 case MemoryCache:
4519 case MapCache:
4520 {
cristy4c08aed2011-07-01 19:47:50 +00004521 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004522 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004523
4524 /*
4525 Read pixels from memory.
4526 */
cristydd341db2010-03-04 19:06:38 +00004527 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004528 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004529 {
cristy48078b12010-09-23 17:11:01 +00004530 length=extent;
cristydd341db2010-03-04 19:06:38 +00004531 rows=1UL;
4532 }
cristyed231572011-07-14 02:18:59 +00004533 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004534 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004535 {
cristy8f036fe2010-09-18 02:02:00 +00004536 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004537 p+=cache_info->number_channels*cache_info->columns;
4538 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004539 }
4540 break;
4541 }
4542 case DiskCache:
4543 {
4544 /*
4545 Read pixels from disk.
4546 */
4547 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4548 {
4549 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4550 cache_info->cache_filename);
4551 return(MagickFalse);
4552 }
cristydd341db2010-03-04 19:06:38 +00004553 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004554 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004555 {
cristy48078b12010-09-23 17:11:01 +00004556 length=extent;
cristydd341db2010-03-04 19:06:38 +00004557 rows=1UL;
4558 }
cristybb503372010-05-27 20:51:26 +00004559 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004560 {
4561 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004562 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004563 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004564 break;
4565 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004566 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004567 }
cristyc11dace2012-01-24 16:39:46 +00004568 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4569 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004570 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004571 {
4572 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4573 cache_info->cache_filename);
4574 return(MagickFalse);
4575 }
4576 break;
4577 }
4578 default:
4579 break;
4580 }
4581 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004582 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004583 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004584 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004585 nexus_info->region.width,(double) nexus_info->region.height,(double)
4586 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004587 return(MagickTrue);
4588}
4589
4590/*
4591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4592% %
4593% %
4594% %
4595+ R e f e r e n c e P i x e l C a c h e %
4596% %
4597% %
4598% %
4599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4600%
4601% ReferencePixelCache() increments the reference count associated with the
4602% pixel cache returning a pointer to the cache.
4603%
4604% The format of the ReferencePixelCache method is:
4605%
4606% Cache ReferencePixelCache(Cache cache_info)
4607%
4608% A description of each parameter follows:
4609%
4610% o cache_info: the pixel cache.
4611%
4612*/
cristya6577ff2011-09-02 19:54:26 +00004613MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004614{
4615 CacheInfo
4616 *cache_info;
4617
4618 assert(cache != (Cache *) NULL);
4619 cache_info=(CacheInfo *) cache;
4620 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004621 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004622 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004623 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004624 return(cache_info);
4625}
4626
4627/*
4628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4629% %
4630% %
4631% %
4632+ S e t P i x e l C a c h e M e t h o d s %
4633% %
4634% %
4635% %
4636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4637%
4638% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4639%
4640% The format of the SetPixelCacheMethods() method is:
4641%
4642% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4643%
4644% A description of each parameter follows:
4645%
4646% o cache: the pixel cache.
4647%
4648% o cache_methods: Specifies a pointer to a CacheMethods structure.
4649%
4650*/
cristya6577ff2011-09-02 19:54:26 +00004651MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004652{
4653 CacheInfo
4654 *cache_info;
4655
4656 GetOneAuthenticPixelFromHandler
4657 get_one_authentic_pixel_from_handler;
4658
4659 GetOneVirtualPixelFromHandler
4660 get_one_virtual_pixel_from_handler;
4661
4662 /*
4663 Set cache pixel methods.
4664 */
4665 assert(cache != (Cache) NULL);
4666 assert(cache_methods != (CacheMethods *) NULL);
4667 cache_info=(CacheInfo *) cache;
4668 assert(cache_info->signature == MagickSignature);
4669 if (cache_info->debug != MagickFalse)
4670 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4671 cache_info->filename);
4672 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4673 cache_info->methods.get_virtual_pixel_handler=
4674 cache_methods->get_virtual_pixel_handler;
4675 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4676 cache_info->methods.destroy_pixel_handler=
4677 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004678 if (cache_methods->get_virtual_metacontent_from_handler !=
4679 (GetVirtualMetacontentFromHandler) NULL)
4680 cache_info->methods.get_virtual_metacontent_from_handler=
4681 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004682 if (cache_methods->get_authentic_pixels_handler !=
4683 (GetAuthenticPixelsHandler) NULL)
4684 cache_info->methods.get_authentic_pixels_handler=
4685 cache_methods->get_authentic_pixels_handler;
4686 if (cache_methods->queue_authentic_pixels_handler !=
4687 (QueueAuthenticPixelsHandler) NULL)
4688 cache_info->methods.queue_authentic_pixels_handler=
4689 cache_methods->queue_authentic_pixels_handler;
4690 if (cache_methods->sync_authentic_pixels_handler !=
4691 (SyncAuthenticPixelsHandler) NULL)
4692 cache_info->methods.sync_authentic_pixels_handler=
4693 cache_methods->sync_authentic_pixels_handler;
4694 if (cache_methods->get_authentic_pixels_from_handler !=
4695 (GetAuthenticPixelsFromHandler) NULL)
4696 cache_info->methods.get_authentic_pixels_from_handler=
4697 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004698 if (cache_methods->get_authentic_metacontent_from_handler !=
4699 (GetAuthenticMetacontentFromHandler) NULL)
4700 cache_info->methods.get_authentic_metacontent_from_handler=
4701 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004702 get_one_virtual_pixel_from_handler=
4703 cache_info->methods.get_one_virtual_pixel_from_handler;
4704 if (get_one_virtual_pixel_from_handler !=
4705 (GetOneVirtualPixelFromHandler) NULL)
4706 cache_info->methods.get_one_virtual_pixel_from_handler=
4707 cache_methods->get_one_virtual_pixel_from_handler;
4708 get_one_authentic_pixel_from_handler=
4709 cache_methods->get_one_authentic_pixel_from_handler;
4710 if (get_one_authentic_pixel_from_handler !=
4711 (GetOneAuthenticPixelFromHandler) NULL)
4712 cache_info->methods.get_one_authentic_pixel_from_handler=
4713 cache_methods->get_one_authentic_pixel_from_handler;
4714}
4715
4716/*
4717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4718% %
4719% %
4720% %
4721+ S e t P i x e l C a c h e N e x u s P i x e l s %
4722% %
4723% %
4724% %
4725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4726%
4727% SetPixelCacheNexusPixels() defines the region of the cache for the
4728% specified cache nexus.
4729%
4730% The format of the SetPixelCacheNexusPixels() method is:
4731%
cristy265a2b22012-05-11 12:48:50 +00004732% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004733% const RectangleInfo *region,NexusInfo *nexus_info,
4734% ExceptionInfo *exception)
4735%
4736% A description of each parameter follows:
4737%
4738% o image: the image.
4739%
cristy265a2b22012-05-11 12:48:50 +00004740% o mode: ReadMode, WriteMode, or IOMode.
4741%
cristy3ed852e2009-09-05 21:47:34 +00004742% o region: A pointer to the RectangleInfo structure that defines the
4743% region of this particular cache nexus.
4744%
4745% o nexus_info: the cache nexus to set.
4746%
4747% o exception: return any errors or warnings in this structure.
4748%
4749*/
cristyabd6e372010-09-15 19:11:26 +00004750
cristyf1832792012-05-08 18:38:18 +00004751static inline MagickBooleanType AcquireCacheNexusPixels(
4752 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4753 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004754{
4755 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4756 return(MagickFalse);
4757 nexus_info->mapped=MagickFalse;
cristye42639a2012-08-23 01:53:24 +00004758 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4759 (size_t) nexus_info->length));
cristy4c08aed2011-07-01 19:47:50 +00004760 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004761 {
4762 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004763 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004764 nexus_info->length);
4765 }
cristy4c08aed2011-07-01 19:47:50 +00004766 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004767 {
4768 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004769 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004770 cache_info->filename);
4771 return(MagickFalse);
4772 }
4773 return(MagickTrue);
4774}
4775
cristyadf82722012-05-11 17:34:16 +00004776static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4777 const MapMode mode)
4778{
cristyfc5845e2012-05-11 18:18:13 +00004779 if (mode == ReadMode)
4780 {
4781 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4782 return;
4783 }
4784 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004785}
4786
cristy265a2b22012-05-11 12:48:50 +00004787static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004788 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4789{
4790 CacheInfo
4791 *cache_info;
4792
4793 MagickBooleanType
4794 status;
4795
cristy3ed852e2009-09-05 21:47:34 +00004796 MagickSizeType
4797 length,
4798 number_pixels;
4799
cristy3ed852e2009-09-05 21:47:34 +00004800 cache_info=(CacheInfo *) image->cache;
4801 assert(cache_info->signature == MagickSignature);
4802 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004803 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004804 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004805 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004806 {
cristybb503372010-05-27 20:51:26 +00004807 ssize_t
cristybad067a2010-02-15 17:20:55 +00004808 x,
4809 y;
cristy3ed852e2009-09-05 21:47:34 +00004810
cristyeaedf062010-05-29 22:36:02 +00004811 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4812 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004813 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4814 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004815 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004816 ((nexus_info->region.width == cache_info->columns) ||
4817 ((nexus_info->region.width % cache_info->columns) == 0)))))
4818 {
4819 MagickOffsetType
4820 offset;
4821
4822 /*
4823 Pixels are accessed directly from memory.
4824 */
4825 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4826 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004827 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004828 offset;
4829 nexus_info->metacontent=(void *) NULL;
4830 if (cache_info->metacontent_extent != 0)
4831 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4832 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004833 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004834 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004835 }
4836 }
4837 /*
4838 Pixels are stored in a cache region until they are synced to the cache.
4839 */
4840 number_pixels=(MagickSizeType) nexus_info->region.width*
4841 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004842 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004843 if (cache_info->metacontent_extent != 0)
4844 length+=number_pixels*cache_info->metacontent_extent;
4845 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004846 {
4847 nexus_info->length=length;
4848 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4849 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004850 {
4851 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004852 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004853 }
cristy3ed852e2009-09-05 21:47:34 +00004854 }
4855 else
4856 if (nexus_info->length != length)
4857 {
4858 RelinquishCacheNexusPixels(nexus_info);
4859 nexus_info->length=length;
4860 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4861 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004862 {
4863 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004864 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004865 }
cristy3ed852e2009-09-05 21:47:34 +00004866 }
4867 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004868 nexus_info->metacontent=(void *) NULL;
4869 if (cache_info->metacontent_extent != 0)
4870 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004871 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004872 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004873 return(nexus_info->pixels);
4874}
4875
4876/*
4877%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4878% %
4879% %
4880% %
4881% 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 %
4882% %
4883% %
4884% %
4885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4886%
4887% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4888% pixel cache and returns the previous setting. A virtual pixel is any pixel
4889% access that is outside the boundaries of the image cache.
4890%
4891% The format of the SetPixelCacheVirtualMethod() method is:
4892%
cristy387430f2012-02-07 13:09:46 +00004893% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4894% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004895%
4896% A description of each parameter follows:
4897%
4898% o image: the image.
4899%
4900% o virtual_pixel_method: choose the type of virtual pixel.
4901%
cristy387430f2012-02-07 13:09:46 +00004902% o exception: return any errors or warnings in this structure.
4903%
cristy3ed852e2009-09-05 21:47:34 +00004904*/
cristy3d4cb882012-02-07 19:11:26 +00004905
4906static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4907 ExceptionInfo *exception)
4908{
4909 CacheInfo
4910 *cache_info;
4911
cristyf2719112012-05-06 18:38:46 +00004912 CacheView
4913 *image_view;
4914
cristy3d4cb882012-02-07 19:11:26 +00004915 MagickBooleanType
4916 status;
4917
4918 ssize_t
4919 y;
4920
4921 assert(image != (Image *) NULL);
4922 assert(image->signature == MagickSignature);
4923 if (image->debug != MagickFalse)
4924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4925 assert(image->cache != (Cache) NULL);
4926 cache_info=(CacheInfo *) image->cache;
4927 assert(cache_info->signature == MagickSignature);
cristy8a46d822012-08-28 23:32:39 +00004928 image->alpha_trait=BlendPixelTrait;
cristy3d4cb882012-02-07 19:11:26 +00004929 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004930 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004931#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +00004932 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00004933 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004934#endif
4935 for (y=0; y < (ssize_t) image->rows; y++)
4936 {
cristy3d4cb882012-02-07 19:11:26 +00004937 register Quantum
4938 *restrict q;
4939
4940 register ssize_t
4941 x;
4942
4943 if (status == MagickFalse)
4944 continue;
cristy23d198a2012-03-13 13:48:08 +00004945 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004946 if (q == (Quantum *) NULL)
4947 {
4948 status=MagickFalse;
4949 continue;
4950 }
4951 for (x=0; x < (ssize_t) image->columns; x++)
4952 {
4953 SetPixelAlpha(image,alpha,q);
4954 q+=GetPixelChannels(image);
4955 }
cristy23d198a2012-03-13 13:48:08 +00004956 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004957 }
cristy23d198a2012-03-13 13:48:08 +00004958 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004959 return(status);
4960}
4961
cristy387430f2012-02-07 13:09:46 +00004962MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4963 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004964{
4965 CacheInfo
4966 *cache_info;
4967
4968 VirtualPixelMethod
4969 method;
4970
4971 assert(image != (Image *) NULL);
4972 assert(image->signature == MagickSignature);
4973 if (image->debug != MagickFalse)
4974 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4975 assert(image->cache != (Cache) NULL);
4976 cache_info=(CacheInfo *) image->cache;
4977 assert(cache_info->signature == MagickSignature);
4978 method=cache_info->virtual_pixel_method;
4979 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy13c10082012-05-29 11:22:12 +00004980 if ((image->columns != 0) && (image->rows != 0))
4981 switch (virtual_pixel_method)
cristy387430f2012-02-07 13:09:46 +00004982 {
cristy13c10082012-05-29 11:22:12 +00004983 case BackgroundVirtualPixelMethod:
4984 {
cristy8a46d822012-08-28 23:32:39 +00004985 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4986 (image->alpha_trait != BlendPixelTrait))
cristy13c10082012-05-29 11:22:12 +00004987 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy6386b792012-06-23 17:44:57 +00004988 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4989 (IsGrayColorspace(image->colorspace) != MagickFalse))
cristyb09db112012-07-11 12:04:31 +00004990 (void) TransformImageColorspace(image,RGBColorspace,exception);
cristy13c10082012-05-29 11:22:12 +00004991 break;
4992 }
4993 case TransparentVirtualPixelMethod:
4994 {
cristy8a46d822012-08-28 23:32:39 +00004995 if (image->alpha_trait != BlendPixelTrait)
cristy13c10082012-05-29 11:22:12 +00004996 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4997 break;
4998 }
4999 default:
5000 break;
cristy387430f2012-02-07 13:09:46 +00005001 }
cristy3ed852e2009-09-05 21:47:34 +00005002 return(method);
5003}
5004
5005/*
5006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5007% %
5008% %
5009% %
5010+ 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 %
5011% %
5012% %
5013% %
5014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5015%
5016% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5017% in-memory or disk cache. The method returns MagickTrue if the pixel region
5018% is synced, otherwise MagickFalse.
5019%
5020% The format of the SyncAuthenticPixelCacheNexus() method is:
5021%
5022% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5023% NexusInfo *nexus_info,ExceptionInfo *exception)
5024%
5025% A description of each parameter follows:
5026%
5027% o image: the image.
5028%
5029% o nexus_info: the cache nexus to sync.
5030%
5031% o exception: return any errors or warnings in this structure.
5032%
5033*/
cristya6577ff2011-09-02 19:54:26 +00005034MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005035 NexusInfo *nexus_info,ExceptionInfo *exception)
5036{
5037 CacheInfo
5038 *cache_info;
5039
5040 MagickBooleanType
5041 status;
5042
5043 /*
5044 Transfer pixels to the cache.
5045 */
5046 assert(image != (Image *) NULL);
5047 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005048 if (image->cache == (Cache) NULL)
5049 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5050 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005051 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005052 if (cache_info->type == UndefinedCache)
5053 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005054 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005055 return(MagickTrue);
5056 assert(cache_info->signature == MagickSignature);
5057 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005058 if ((cache_info->metacontent_extent != 0) &&
5059 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005060 return(MagickFalse);
5061 return(status);
5062}
5063
5064/*
5065%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5066% %
5067% %
5068% %
5069+ S y n c A u t h e n t i c P i x e l C a c h e %
5070% %
5071% %
5072% %
5073%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5074%
5075% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5076% or disk cache. The method returns MagickTrue if the pixel region is synced,
5077% otherwise MagickFalse.
5078%
5079% The format of the SyncAuthenticPixelsCache() method is:
5080%
5081% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5082% ExceptionInfo *exception)
5083%
5084% A description of each parameter follows:
5085%
5086% o image: the image.
5087%
5088% o exception: return any errors or warnings in this structure.
5089%
5090*/
5091static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5092 ExceptionInfo *exception)
5093{
5094 CacheInfo
5095 *cache_info;
5096
cristy5c9e6f22010-09-17 17:31:01 +00005097 const int
5098 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005099
cristy4c08aed2011-07-01 19:47:50 +00005100 MagickBooleanType
5101 status;
5102
cristye7cc7cf2010-09-21 13:26:47 +00005103 assert(image != (Image *) NULL);
5104 assert(image->signature == MagickSignature);
5105 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005106 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005107 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005108 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005109 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5110 exception);
5111 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005112}
5113
5114/*
5115%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5116% %
5117% %
5118% %
5119% S y n c A u t h e n t i c P i x e l s %
5120% %
5121% %
5122% %
5123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5124%
5125% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5126% The method returns MagickTrue if the pixel region is flushed, otherwise
5127% MagickFalse.
5128%
5129% The format of the SyncAuthenticPixels() method is:
5130%
5131% MagickBooleanType SyncAuthenticPixels(Image *image,
5132% ExceptionInfo *exception)
5133%
5134% A description of each parameter follows:
5135%
5136% o image: the image.
5137%
5138% o exception: return any errors or warnings in this structure.
5139%
5140*/
5141MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5142 ExceptionInfo *exception)
5143{
5144 CacheInfo
5145 *cache_info;
5146
cristy2036f5c2010-09-19 21:18:17 +00005147 const int
5148 id = GetOpenMPThreadId();
5149
cristy4c08aed2011-07-01 19:47:50 +00005150 MagickBooleanType
5151 status;
5152
cristy3ed852e2009-09-05 21:47:34 +00005153 assert(image != (Image *) NULL);
5154 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005155 assert(image->cache != (Cache) NULL);
5156 cache_info=(CacheInfo *) image->cache;
5157 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005158 if (cache_info->methods.sync_authentic_pixels_handler !=
5159 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005160 {
5161 status=cache_info->methods.sync_authentic_pixels_handler(image,
5162 exception);
5163 return(status);
5164 }
cristy2036f5c2010-09-19 21:18:17 +00005165 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005166 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5167 exception);
5168 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005169}
5170
5171/*
5172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5173% %
5174% %
5175% %
cristyd1dd6e42011-09-04 01:46:08 +00005176+ 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 +00005177% %
5178% %
5179% %
5180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5181%
5182% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5183% The method returns MagickTrue if the pixel region is flushed, otherwise
5184% MagickFalse.
5185%
5186% The format of the SyncImagePixelCache() method is:
5187%
5188% MagickBooleanType SyncImagePixelCache(Image *image,
5189% ExceptionInfo *exception)
5190%
5191% A description of each parameter follows:
5192%
5193% o image: the image.
5194%
5195% o exception: return any errors or warnings in this structure.
5196%
5197*/
cristyd1dd6e42011-09-04 01:46:08 +00005198MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005199 ExceptionInfo *exception)
5200{
5201 CacheInfo
5202 *cache_info;
5203
5204 assert(image != (Image *) NULL);
5205 assert(exception != (ExceptionInfo *) NULL);
5206 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5207 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5208}
5209
5210/*
5211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5212% %
5213% %
5214% %
cristy4c08aed2011-07-01 19:47:50 +00005215+ 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 +00005216% %
5217% %
5218% %
5219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5220%
cristy4c08aed2011-07-01 19:47:50 +00005221% WritePixelCacheMetacontent() writes the meta-content to the specified region
5222% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005223%
cristy4c08aed2011-07-01 19:47:50 +00005224% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005225%
cristy4c08aed2011-07-01 19:47:50 +00005226% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005227% NexusInfo *nexus_info,ExceptionInfo *exception)
5228%
5229% A description of each parameter follows:
5230%
5231% o cache_info: the pixel cache.
5232%
cristy4c08aed2011-07-01 19:47:50 +00005233% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005234%
5235% o exception: return any errors or warnings in this structure.
5236%
5237*/
cristy4c08aed2011-07-01 19:47:50 +00005238static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005239 NexusInfo *nexus_info,ExceptionInfo *exception)
5240{
5241 MagickOffsetType
5242 count,
5243 offset;
5244
5245 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005246 extent,
5247 length;
cristy3ed852e2009-09-05 21:47:34 +00005248
cristy4c08aed2011-07-01 19:47:50 +00005249 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005250 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005251
cristybb503372010-05-27 20:51:26 +00005252 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005253 y;
5254
cristybb503372010-05-27 20:51:26 +00005255 size_t
cristy3ed852e2009-09-05 21:47:34 +00005256 rows;
5257
cristy4c08aed2011-07-01 19:47:50 +00005258 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005259 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005260 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005261 return(MagickTrue);
5262 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5263 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005264 length=(MagickSizeType) nexus_info->region.width*
5265 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005266 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005267 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005268 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005269 switch (cache_info->type)
5270 {
5271 case MemoryCache:
5272 case MapCache:
5273 {
cristy4c08aed2011-07-01 19:47:50 +00005274 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005275 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005276
5277 /*
cristy4c08aed2011-07-01 19:47:50 +00005278 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005279 */
cristydd341db2010-03-04 19:06:38 +00005280 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005281 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005282 {
cristy48078b12010-09-23 17:11:01 +00005283 length=extent;
cristydd341db2010-03-04 19:06:38 +00005284 rows=1UL;
5285 }
cristy4c08aed2011-07-01 19:47:50 +00005286 q=(unsigned char *) cache_info->metacontent+offset*
5287 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005288 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005289 {
cristy8f036fe2010-09-18 02:02:00 +00005290 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005291 p+=nexus_info->region.width*cache_info->metacontent_extent;
5292 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005293 }
5294 break;
5295 }
5296 case DiskCache:
5297 {
5298 /*
cristy4c08aed2011-07-01 19:47:50 +00005299 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005300 */
5301 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5302 {
5303 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5304 cache_info->cache_filename);
5305 return(MagickFalse);
5306 }
cristydd341db2010-03-04 19:06:38 +00005307 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005308 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005309 {
cristy48078b12010-09-23 17:11:01 +00005310 length=extent;
cristydd341db2010-03-04 19:06:38 +00005311 rows=1UL;
5312 }
cristy48078b12010-09-23 17:11:01 +00005313 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005314 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005315 {
cristy48078b12010-09-23 17:11:01 +00005316 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005317 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005318 cache_info->metacontent_extent,length,(const unsigned char *) p);
5319 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005320 break;
cristy4c08aed2011-07-01 19:47:50 +00005321 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005322 offset+=cache_info->columns;
5323 }
cristyc11dace2012-01-24 16:39:46 +00005324 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5325 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005326 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005327 {
5328 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5329 cache_info->cache_filename);
5330 return(MagickFalse);
5331 }
5332 break;
5333 }
5334 default:
5335 break;
5336 }
5337 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005338 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005339 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005340 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005341 nexus_info->region.width,(double) nexus_info->region.height,(double)
5342 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005343 return(MagickTrue);
5344}
5345
5346/*
5347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5348% %
5349% %
5350% %
5351+ W r i t e C a c h e P i x e l s %
5352% %
5353% %
5354% %
5355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5356%
5357% WritePixelCachePixels() writes image pixels to the specified region of the
5358% pixel cache.
5359%
5360% The format of the WritePixelCachePixels() method is:
5361%
5362% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5363% NexusInfo *nexus_info,ExceptionInfo *exception)
5364%
5365% A description of each parameter follows:
5366%
5367% o cache_info: the pixel cache.
5368%
5369% o nexus_info: the cache nexus to write the pixels.
5370%
5371% o exception: return any errors or warnings in this structure.
5372%
5373*/
5374static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5375 NexusInfo *nexus_info,ExceptionInfo *exception)
5376{
5377 MagickOffsetType
5378 count,
5379 offset;
5380
5381 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005382 extent,
5383 length;
cristy3ed852e2009-09-05 21:47:34 +00005384
cristy4c08aed2011-07-01 19:47:50 +00005385 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005386 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005387
cristybb503372010-05-27 20:51:26 +00005388 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005389 y;
5390
cristybb503372010-05-27 20:51:26 +00005391 size_t
cristy3ed852e2009-09-05 21:47:34 +00005392 rows;
5393
cristy4c08aed2011-07-01 19:47:50 +00005394 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005395 return(MagickTrue);
5396 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5397 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005398 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005399 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005400 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005401 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005402 p=nexus_info->pixels;
5403 switch (cache_info->type)
5404 {
5405 case MemoryCache:
5406 case MapCache:
5407 {
cristy4c08aed2011-07-01 19:47:50 +00005408 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005409 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005410
5411 /*
5412 Write pixels to memory.
5413 */
cristydd341db2010-03-04 19:06:38 +00005414 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005415 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005416 {
cristy48078b12010-09-23 17:11:01 +00005417 length=extent;
cristydd341db2010-03-04 19:06:38 +00005418 rows=1UL;
5419 }
cristyed231572011-07-14 02:18:59 +00005420 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005421 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005422 {
cristy8f036fe2010-09-18 02:02:00 +00005423 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005424 p+=nexus_info->region.width*cache_info->number_channels;
5425 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005426 }
5427 break;
5428 }
5429 case DiskCache:
5430 {
5431 /*
5432 Write pixels to disk.
5433 */
5434 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5435 {
5436 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5437 cache_info->cache_filename);
5438 return(MagickFalse);
5439 }
cristydd341db2010-03-04 19:06:38 +00005440 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005441 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005442 {
cristy48078b12010-09-23 17:11:01 +00005443 length=extent;
cristydd341db2010-03-04 19:06:38 +00005444 rows=1UL;
5445 }
cristybb503372010-05-27 20:51:26 +00005446 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005447 {
5448 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005449 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005450 p);
5451 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005452 break;
cristyed231572011-07-14 02:18:59 +00005453 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005454 offset+=cache_info->columns;
5455 }
cristyc11dace2012-01-24 16:39:46 +00005456 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5457 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005458 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005459 {
5460 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5461 cache_info->cache_filename);
5462 return(MagickFalse);
5463 }
5464 break;
5465 }
5466 default:
5467 break;
5468 }
5469 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005470 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005471 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005472 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005473 nexus_info->region.width,(double) nexus_info->region.height,(double)
5474 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005475 return(MagickTrue);
5476}