blob: d45c1a390ebde792d33866657f95cff320e5b684 [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
554 if (count > 0)
555 continue;
556 count=0;
557 if (errno != EINTR)
558 {
559 i=(-1);
560 break;
561 }
562 }
563#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000564 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000565#endif
566 return(i);
567}
568
cristyf1832792012-05-08 18:38:18 +0000569static inline MagickOffsetType WritePixelCacheRegion(
570 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
571 const MagickSizeType length,const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000572{
573 register MagickOffsetType
574 i;
575
576 ssize_t
577 count;
578
579#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000580 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000581 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000582 {
cristyf84a1932010-01-03 18:00:18 +0000583 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000584 return((MagickOffsetType) -1);
585 }
586#endif
587 count=0;
588 for (i=0; i < (MagickOffsetType) length; i+=count)
589 {
590#if !defined(MAGICKCORE_HAVE_PWRITE)
591 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
592 (MagickSizeType) SSIZE_MAX));
593#else
594 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000595 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000596#endif
597 if (count > 0)
598 continue;
599 count=0;
600 if (errno != EINTR)
601 {
602 i=(-1);
603 break;
604 }
605 }
606#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000607 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000608#endif
609 return(i);
610}
611
cristy4c08aed2011-07-01 19:47:50 +0000612static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000613 CacheInfo *cache_info,ExceptionInfo *exception)
614{
615 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000616 count;
cristy3ed852e2009-09-05 21:47:34 +0000617
cristy4c08aed2011-07-01 19:47:50 +0000618 register MagickOffsetType
619 i;
cristye076a6e2010-08-15 19:59:43 +0000620
cristybb503372010-05-27 20:51:26 +0000621 size_t
cristy4c08aed2011-07-01 19:47:50 +0000622 length;
cristy3ed852e2009-09-05 21:47:34 +0000623
cristy4c08aed2011-07-01 19:47:50 +0000624 unsigned char
625 *blob;
626
627 /*
628 Clone pixel cache (both caches on disk).
629 */
cristy3ed852e2009-09-05 21:47:34 +0000630 if (cache_info->debug != MagickFalse)
631 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000632 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000633 sizeof(*blob));
634 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000635 {
cristy4c08aed2011-07-01 19:47:50 +0000636 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000637 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000638 cache_info->filename);
639 return(MagickFalse);
640 }
cristy3dedf062011-07-02 14:07:40 +0000641 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000642 {
643 blob=(unsigned char *) RelinquishMagickMemory(blob);
644 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
645 cache_info->cache_filename);
646 return(MagickFalse);
647 }
cristy3dedf062011-07-02 14:07:40 +0000648 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000649 {
650 (void) ClosePixelCacheOnDisk(cache_info);
651 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000652 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
653 clone_info->cache_filename);
654 return(MagickFalse);
655 }
cristy4c08aed2011-07-01 19:47:50 +0000656 count=0;
657 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000658 {
cristy4c08aed2011-07-01 19:47:50 +0000659 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
660 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
661 blob);
662 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000663 {
cristy4c08aed2011-07-01 19:47:50 +0000664 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
665 cache_info->cache_filename);
666 break;
cristy3ed852e2009-09-05 21:47:34 +0000667 }
cristy4c08aed2011-07-01 19:47:50 +0000668 length=(size_t) count;
669 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
670 if ((MagickSizeType) count != length)
671 {
672 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
673 clone_info->cache_filename);
674 break;
675 }
676 }
677 (void) ClosePixelCacheOnDisk(clone_info);
678 (void) ClosePixelCacheOnDisk(cache_info);
679 blob=(unsigned char *) RelinquishMagickMemory(blob);
680 if (i < (MagickOffsetType) cache_info->length)
681 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000682 return(MagickTrue);
683}
684
cristyfd24a062012-01-02 14:46:34 +0000685static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000686 CacheInfo *cache_info,ExceptionInfo *exception)
687{
688 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000689 count;
cristy3ed852e2009-09-05 21:47:34 +0000690
cristy4c08aed2011-07-01 19:47:50 +0000691 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000692 {
cristy3ed852e2009-09-05 21:47:34 +0000693 /*
cristy4c08aed2011-07-01 19:47:50 +0000694 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000695 */
cristy4c08aed2011-07-01 19:47:50 +0000696 if (cache_info->debug != MagickFalse)
697 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
698 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
699 cache_info->length);
700 return(MagickTrue);
701 }
702 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
703 {
704 /*
705 Clone pixel cache (one cache on disk, one in memory).
706 */
707 if (cache_info->debug != MagickFalse)
708 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
709 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000710 {
cristy4c08aed2011-07-01 19:47:50 +0000711 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000712 cache_info->cache_filename);
713 return(MagickFalse);
714 }
cristy4c08aed2011-07-01 19:47:50 +0000715 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
716 cache_info->length,(unsigned char *) clone_info->pixels);
717 (void) ClosePixelCacheOnDisk(cache_info);
718 if ((MagickSizeType) count != cache_info->length)
719 {
720 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
721 cache_info->cache_filename);
722 return(MagickFalse);
723 }
724 return(MagickTrue);
725 }
726 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
727 {
728 /*
729 Clone pixel cache (one cache on disk, one in memory).
730 */
731 if (clone_info->debug != MagickFalse)
732 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
733 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
734 {
735 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
736 clone_info->cache_filename);
737 return(MagickFalse);
738 }
739 count=WritePixelCacheRegion(clone_info,clone_info->offset,
740 clone_info->length,(unsigned char *) cache_info->pixels);
741 (void) ClosePixelCacheOnDisk(clone_info);
742 if ((MagickSizeType) count != clone_info->length)
743 {
744 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
745 clone_info->cache_filename);
746 return(MagickFalse);
747 }
748 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000749 }
750 /*
cristy4c08aed2011-07-01 19:47:50 +0000751 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000752 */
cristy4c08aed2011-07-01 19:47:50 +0000753 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000754}
755
cristyfd24a062012-01-02 14:46:34 +0000756static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000757 CacheInfo *cache_info,ExceptionInfo *exception)
758{
cristy4c08aed2011-07-01 19:47:50 +0000759 MagickBooleanType
760 status;
cristy3ed852e2009-09-05 21:47:34 +0000761
cristy4c08aed2011-07-01 19:47:50 +0000762 MagickOffsetType
763 cache_offset,
764 clone_offset,
765 count;
766
767 register ssize_t
768 x;
769
cristyfd24a062012-01-02 14:46:34 +0000770 register unsigned char
771 *p;
772
cristy4c08aed2011-07-01 19:47:50 +0000773 size_t
cristy3ed852e2009-09-05 21:47:34 +0000774 length;
775
cristy4c08aed2011-07-01 19:47:50 +0000776 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000777 y;
778
cristy4c08aed2011-07-01 19:47:50 +0000779 unsigned char
780 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000781
cristy4c08aed2011-07-01 19:47:50 +0000782 /*
783 Clone pixel cache (unoptimized).
784 */
cristy3ed852e2009-09-05 21:47:34 +0000785 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000786 {
cristy4c08aed2011-07-01 19:47:50 +0000787 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
789 else
790 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
792 else
793 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
794 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
795 else
796 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
797 }
cristyed231572011-07-14 02:18:59 +0000798 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
799 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000800 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000801 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000802 if (blob == (unsigned char *) NULL)
803 {
804 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000805 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000806 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000807 return(MagickFalse);
808 }
cristy4c08aed2011-07-01 19:47:50 +0000809 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
810 cache_offset=0;
811 clone_offset=0;
812 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000813 {
cristy4c08aed2011-07-01 19:47:50 +0000814 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000815 {
cristy4c08aed2011-07-01 19:47:50 +0000816 blob=(unsigned char *) RelinquishMagickMemory(blob);
817 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000818 cache_info->cache_filename);
819 return(MagickFalse);
820 }
cristy4c08aed2011-07-01 19:47:50 +0000821 cache_offset=cache_info->offset;
822 }
823 if (clone_info->type == DiskCache)
824 {
cristy3dedf062011-07-02 14:07:40 +0000825 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000826 {
cristy4c08aed2011-07-01 19:47:50 +0000827 blob=(unsigned char *) RelinquishMagickMemory(blob);
828 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
829 clone_info->cache_filename);
830 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000831 }
cristy4c08aed2011-07-01 19:47:50 +0000832 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000833 }
834 /*
cristy4c08aed2011-07-01 19:47:50 +0000835 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000836 */
cristy4c08aed2011-07-01 19:47:50 +0000837 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000838 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000839 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000840 {
cristy4c08aed2011-07-01 19:47:50 +0000841 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000842 {
cristy9e0719b2011-12-29 03:45:45 +0000843 register ssize_t
844 i;
845
cristy3ed852e2009-09-05 21:47:34 +0000846 /*
cristy4c08aed2011-07-01 19:47:50 +0000847 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000848 */
cristyed231572011-07-14 02:18:59 +0000849 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000850 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000851 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000852 else
853 {
cristyfd24a062012-01-02 14:46:34 +0000854 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000855 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000856 {
cristy4c08aed2011-07-01 19:47:50 +0000857 status=MagickFalse;
858 break;
cristy3ed852e2009-09-05 21:47:34 +0000859 }
860 }
cristy4c08aed2011-07-01 19:47:50 +0000861 cache_offset+=length;
862 if ((y < (ssize_t) clone_info->rows) &&
863 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000864 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
cristy9e0719b2011-12-29 03:45:45 +0000866 PixelChannel
867 channel;
868
869 PixelTrait
870 traits;
871
872 ssize_t
873 offset;
874
cristy4c08aed2011-07-01 19:47:50 +0000875 /*
cristy3b8fe922011-12-29 18:56:23 +0000876 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000877 */
cristy9e0719b2011-12-29 03:45:45 +0000878 channel=clone_info->channel_map[i].channel;
879 traits=cache_info->channel_map[channel].traits;
880 if (traits == UndefinedPixelTrait)
881 {
cristy0f4425e2011-12-31 20:33:02 +0000882 clone_offset+=sizeof(Quantum);
883 continue;
cristy9e0719b2011-12-29 03:45:45 +0000884 }
cristy0f4425e2011-12-31 20:33:02 +0000885 offset=cache_info->channel_map[channel].offset;
886 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000887 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
888 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000889 else
890 {
cristy0f4425e2011-12-31 20:33:02 +0000891 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000892 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000893 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000894 {
cristy0f4425e2011-12-31 20:33:02 +0000895 status=MagickFalse;
896 break;
cristy4c08aed2011-07-01 19:47:50 +0000897 }
898 }
cristy9e0719b2011-12-29 03:45:45 +0000899 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000900 }
901 }
cristyac245f82012-05-05 17:13:57 +0000902 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000903 {
904 /*
905 Set remaining columns as undefined.
906 */
cristy888e6132012-04-23 19:54:54 +0000907 length=clone_info->number_channels*sizeof(Quantum);
908 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
909 for ( ; x < (ssize_t) clone_info->columns; x++)
910 {
911 if (clone_info->type != DiskCache)
912 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
913 blob,length);
914 else
915 {
916 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
917 if ((MagickSizeType) count != length)
918 {
919 status=MagickFalse;
920 break;
cristye04362f2012-04-23 15:33:05 +0000921 }
cristy888e6132012-04-23 19:54:54 +0000922 }
923 clone_offset+=length;
924 }
cristye04362f2012-04-23 15:33:05 +0000925 }
cristy4c08aed2011-07-01 19:47:50 +0000926 }
cristyed231572011-07-14 02:18:59 +0000927 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000928 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
929 for ( ; y < (ssize_t) clone_info->rows; y++)
930 {
931 /*
cristy9e0719b2011-12-29 03:45:45 +0000932 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000933 */
934 for (x=0; x < (ssize_t) clone_info->columns; x++)
935 {
936 if (clone_info->type != DiskCache)
937 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
938 length);
939 else
940 {
941 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
942 if ((MagickSizeType) count != length)
943 {
944 status=MagickFalse;
945 break;
946 }
947 }
948 clone_offset+=length;
949 }
950 }
cristy9e0719b2011-12-29 03:45:45 +0000951 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000952 (clone_info->metacontent_extent != 0))
953 {
954 /*
955 Clone metacontent.
956 */
957 for (y=0; y < (ssize_t) cache_info->rows; y++)
958 {
959 for (x=0; x < (ssize_t) cache_info->columns; x++)
960 {
961 /*
962 Read a set of metacontent.
963 */
964 length=cache_info->metacontent_extent;
965 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000966 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000967 else
968 {
cristyfd24a062012-01-02 14:46:34 +0000969 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000970 if ((MagickSizeType) count != length)
971 {
972 status=MagickFalse;
973 break;
974 }
975 }
976 cache_offset+=length;
977 if ((y < (ssize_t) clone_info->rows) &&
978 (x < (ssize_t) clone_info->columns))
979 {
980 /*
981 Write a set of metacontent.
982 */
983 length=clone_info->metacontent_extent;
984 if (clone_info->type != DiskCache)
985 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000986 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000987 else
988 {
cristyfd24a062012-01-02 14:46:34 +0000989 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000990 if ((MagickSizeType) count != length)
991 {
992 status=MagickFalse;
993 break;
994 }
995 }
996 clone_offset+=length;
997 }
998 }
999 length=clone_info->metacontent_extent;
1000 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1001 for ( ; x < (ssize_t) clone_info->columns; x++)
1002 {
1003 /*
cristy9e0719b2011-12-29 03:45:45 +00001004 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001005 */
1006 if (clone_info->type != DiskCache)
1007 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1008 blob,length);
1009 else
1010 {
cristy208b1002011-08-07 18:51:50 +00001011 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001012 if ((MagickSizeType) count != length)
1013 {
1014 status=MagickFalse;
1015 break;
1016 }
1017 }
1018 clone_offset+=length;
1019 }
1020 }
cristyac245f82012-05-05 17:13:57 +00001021 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001022 {
cristye04362f2012-04-23 15:33:05 +00001023 /*
1024 Set remaining rows as undefined.
1025 */
cristy888e6132012-04-23 19:54:54 +00001026 length=clone_info->metacontent_extent;
1027 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1028 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001029 {
cristy888e6132012-04-23 19:54:54 +00001030 for (x=0; x < (ssize_t) clone_info->columns; x++)
1031 {
1032 if (clone_info->type != DiskCache)
1033 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1034 blob,length);
1035 else
1036 {
1037 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1038 blob);
1039 if ((MagickSizeType) count != length)
1040 {
1041 status=MagickFalse;
1042 break;
1043 }
1044 }
1045 clone_offset+=length;
1046 }
cristye04362f2012-04-23 15:33:05 +00001047 }
cristy4c08aed2011-07-01 19:47:50 +00001048 }
cristy4c08aed2011-07-01 19:47:50 +00001049 }
1050 if (clone_info->type == DiskCache)
1051 (void) ClosePixelCacheOnDisk(clone_info);
1052 if (cache_info->type == DiskCache)
1053 (void) ClosePixelCacheOnDisk(cache_info);
1054 blob=(unsigned char *) RelinquishMagickMemory(blob);
1055 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001056}
1057
1058static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1059 CacheInfo *cache_info,ExceptionInfo *exception)
1060{
cristy3dfccb22011-12-28 21:47:20 +00001061 PixelChannelMap
1062 *p,
1063 *q;
1064
cristy5a7fbfb2010-11-06 16:10:59 +00001065 if (cache_info->type == PingCache)
1066 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001067 p=cache_info->channel_map;
1068 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001069 if ((cache_info->columns == clone_info->columns) &&
1070 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001071 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001072 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001073 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001074 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1075 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001076}
1077
1078/*
1079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1080% %
1081% %
1082% %
1083+ C l o n e P i x e l C a c h e M e t h o d s %
1084% %
1085% %
1086% %
1087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088%
1089% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1090% another.
1091%
1092% The format of the ClonePixelCacheMethods() method is:
1093%
1094% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1095%
1096% A description of each parameter follows:
1097%
1098% o clone: Specifies a pointer to a Cache structure.
1099%
1100% o cache: the pixel cache.
1101%
1102*/
cristya6577ff2011-09-02 19:54:26 +00001103MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001104{
1105 CacheInfo
1106 *cache_info,
1107 *source_info;
1108
1109 assert(clone != (Cache) NULL);
1110 source_info=(CacheInfo *) clone;
1111 assert(source_info->signature == MagickSignature);
1112 if (source_info->debug != MagickFalse)
1113 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1114 source_info->filename);
1115 assert(cache != (Cache) NULL);
1116 cache_info=(CacheInfo *) cache;
1117 assert(cache_info->signature == MagickSignature);
1118 source_info->methods=cache_info->methods;
1119}
1120
1121/*
1122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1123% %
1124% %
1125% %
1126+ D e s t r o y I m a g e P i x e l C a c h e %
1127% %
1128% %
1129% %
1130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1131%
1132% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1133%
1134% The format of the DestroyImagePixelCache() method is:
1135%
1136% void DestroyImagePixelCache(Image *image)
1137%
1138% A description of each parameter follows:
1139%
1140% o image: the image.
1141%
1142*/
1143static void DestroyImagePixelCache(Image *image)
1144{
1145 assert(image != (Image *) NULL);
1146 assert(image->signature == MagickSignature);
1147 if (image->debug != MagickFalse)
1148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1149 if (image->cache == (void *) NULL)
1150 return;
1151 image->cache=DestroyPixelCache(image->cache);
1152}
1153
1154/*
1155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1156% %
1157% %
1158% %
1159+ D e s t r o y I m a g e P i x e l s %
1160% %
1161% %
1162% %
1163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1164%
1165% DestroyImagePixels() deallocates memory associated with the pixel cache.
1166%
1167% The format of the DestroyImagePixels() method is:
1168%
1169% void DestroyImagePixels(Image *image)
1170%
1171% A description of each parameter follows:
1172%
1173% o image: the image.
1174%
1175*/
1176MagickExport void DestroyImagePixels(Image *image)
1177{
1178 CacheInfo
1179 *cache_info;
1180
1181 assert(image != (const Image *) NULL);
1182 assert(image->signature == MagickSignature);
1183 if (image->debug != MagickFalse)
1184 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1185 assert(image->cache != (Cache) NULL);
1186 cache_info=(CacheInfo *) image->cache;
1187 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001188 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1189 {
1190 cache_info->methods.destroy_pixel_handler(image);
1191 return;
1192 }
cristy2036f5c2010-09-19 21:18:17 +00001193 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001194}
1195
1196/*
1197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198% %
1199% %
1200% %
1201+ D e s t r o y P i x e l C a c h e %
1202% %
1203% %
1204% %
1205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206%
1207% DestroyPixelCache() deallocates memory associated with the pixel cache.
1208%
1209% The format of the DestroyPixelCache() method is:
1210%
1211% Cache DestroyPixelCache(Cache cache)
1212%
1213% A description of each parameter follows:
1214%
1215% o cache: the pixel cache.
1216%
1217*/
1218
1219static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1220{
1221 switch (cache_info->type)
1222 {
1223 case MemoryCache:
1224 {
1225 if (cache_info->mapped == MagickFalse)
cristy9dd0b6f2012-08-01 14:38:43 +00001226 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
cristy3ed852e2009-09-05 21:47:34 +00001227 cache_info->pixels);
1228 else
cristy4c08aed2011-07-01 19:47:50 +00001229 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001230 (size_t) cache_info->length);
1231 RelinquishMagickResource(MemoryResource,cache_info->length);
1232 break;
1233 }
1234 case MapCache:
1235 {
cristy4c08aed2011-07-01 19:47:50 +00001236 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001237 cache_info->length);
1238 RelinquishMagickResource(MapResource,cache_info->length);
1239 }
1240 case DiskCache:
1241 {
1242 if (cache_info->file != -1)
1243 (void) ClosePixelCacheOnDisk(cache_info);
1244 RelinquishMagickResource(DiskResource,cache_info->length);
1245 break;
1246 }
1247 default:
1248 break;
1249 }
1250 cache_info->type=UndefinedCache;
1251 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001252 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001253}
1254
cristya6577ff2011-09-02 19:54:26 +00001255MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001256{
1257 CacheInfo
1258 *cache_info;
1259
cristy3ed852e2009-09-05 21:47:34 +00001260 assert(cache != (Cache) NULL);
1261 cache_info=(CacheInfo *) cache;
1262 assert(cache_info->signature == MagickSignature);
1263 if (cache_info->debug != MagickFalse)
1264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1265 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001266 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001267 cache_info->reference_count--;
1268 if (cache_info->reference_count != 0)
1269 {
cristyf84a1932010-01-03 18:00:18 +00001270 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001271 return((Cache) NULL);
1272 }
cristyf84a1932010-01-03 18:00:18 +00001273 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001274 if (cache_info->debug != MagickFalse)
1275 {
1276 char
1277 message[MaxTextExtent];
1278
cristyb51dff52011-05-19 16:55:47 +00001279 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001280 cache_info->filename);
1281 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1282 }
cristyc2e1bdd2009-09-10 23:43:34 +00001283 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1284 (cache_info->type != DiskCache)))
1285 RelinquishPixelCachePixels(cache_info);
1286 else
1287 {
1288 RelinquishPixelCachePixels(cache_info);
1289 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1290 }
cristy3ed852e2009-09-05 21:47:34 +00001291 *cache_info->cache_filename='\0';
1292 if (cache_info->nexus_info != (NexusInfo **) NULL)
1293 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1294 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001295 if (cache_info->random_info != (RandomInfo *) NULL)
1296 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001297 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1298 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1299 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1300 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001301 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001302 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001303 cache=(Cache) NULL;
1304 return(cache);
1305}
1306
1307/*
1308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309% %
1310% %
1311% %
1312+ D e s t r o y P i x e l C a c h e N e x u s %
1313% %
1314% %
1315% %
1316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1317%
1318% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1319%
1320% The format of the DestroyPixelCacheNexus() method is:
1321%
1322% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001323% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001324%
1325% A description of each parameter follows:
1326%
1327% o nexus_info: the nexus to destroy.
1328%
1329% o number_threads: the number of nexus threads.
1330%
1331*/
1332
1333static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1334{
1335 if (nexus_info->mapped == MagickFalse)
cristy9dd0b6f2012-08-01 14:38:43 +00001336 (void) RelinquishAlignedMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001337 else
1338 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001339 nexus_info->cache=(Quantum *) NULL;
1340 nexus_info->pixels=(Quantum *) NULL;
1341 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001342 nexus_info->length=0;
1343 nexus_info->mapped=MagickFalse;
1344}
1345
cristya6577ff2011-09-02 19:54:26 +00001346MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001347 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001348{
cristybb503372010-05-27 20:51:26 +00001349 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001350 i;
1351
1352 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001353 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001354 {
cristy4c08aed2011-07-01 19:47:50 +00001355 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001356 RelinquishCacheNexusPixels(nexus_info[i]);
1357 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001358 }
cristye5f87c82012-02-14 12:44:17 +00001359 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001360 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001361 return(nexus_info);
1362}
1363
1364/*
1365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366% %
1367% %
1368% %
cristy4c08aed2011-07-01 19:47:50 +00001369% G e t A u t h e n t i c M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00001370% %
1371% %
1372% %
1373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1374%
cristy4c08aed2011-07-01 19:47:50 +00001375% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1376% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1377% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001378%
cristy4c08aed2011-07-01 19:47:50 +00001379% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001380%
cristy4c08aed2011-07-01 19:47:50 +00001381% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001382%
1383% A description of each parameter follows:
1384%
1385% o image: the image.
1386%
1387*/
cristy4c08aed2011-07-01 19:47:50 +00001388MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001389{
1390 CacheInfo
1391 *cache_info;
1392
cristy5c9e6f22010-09-17 17:31:01 +00001393 const int
1394 id = GetOpenMPThreadId();
1395
cristy4c08aed2011-07-01 19:47:50 +00001396 void
1397 *metacontent;
1398
cristye7cc7cf2010-09-21 13:26:47 +00001399 assert(image != (const Image *) NULL);
1400 assert(image->signature == MagickSignature);
1401 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001402 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001403 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001404 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1405 (GetAuthenticMetacontentFromHandler) NULL)
1406 {
1407 metacontent=cache_info->methods.
1408 get_authentic_metacontent_from_handler(image);
1409 return(metacontent);
1410 }
cristy6ebe97c2010-07-03 01:17:28 +00001411 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001412 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1413 cache_info->nexus_info[id]);
1414 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001415}
1416
1417/*
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419% %
1420% %
1421% %
cristy4c08aed2011-07-01 19:47:50 +00001422+ G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00001423% %
1424% %
1425% %
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427%
cristy4c08aed2011-07-01 19:47:50 +00001428% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1429% with the last call to QueueAuthenticPixelsCache() or
1430% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001431%
cristy4c08aed2011-07-01 19:47:50 +00001432% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001433%
cristy4c08aed2011-07-01 19:47:50 +00001434% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001435%
1436% A description of each parameter follows:
1437%
1438% o image: the image.
1439%
1440*/
cristy4c08aed2011-07-01 19:47:50 +00001441static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001442{
1443 CacheInfo
1444 *cache_info;
1445
cristy2036f5c2010-09-19 21:18:17 +00001446 const int
1447 id = GetOpenMPThreadId();
1448
cristy4c08aed2011-07-01 19:47:50 +00001449 void
1450 *metacontent;
1451
cristy3ed852e2009-09-05 21:47:34 +00001452 assert(image != (const Image *) NULL);
1453 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001454 assert(image->cache != (Cache) NULL);
1455 cache_info=(CacheInfo *) image->cache;
1456 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001457 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001458 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1459 cache_info->nexus_info[id]);
1460 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001461}
1462
1463/*
1464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465% %
1466% %
1467% %
1468+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1469% %
1470% %
1471% %
1472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1473%
1474% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1475% disk pixel cache as defined by the geometry parameters. A pointer to the
1476% pixels is returned if the pixels are transferred, otherwise a NULL is
1477% returned.
1478%
1479% The format of the GetAuthenticPixelCacheNexus() method is:
1480%
cristy4c08aed2011-07-01 19:47:50 +00001481% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001482% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001483% NexusInfo *nexus_info,ExceptionInfo *exception)
1484%
1485% A description of each parameter follows:
1486%
1487% o image: the image.
1488%
1489% o x,y,columns,rows: These values define the perimeter of a region of
1490% pixels.
1491%
1492% o nexus_info: the cache nexus to return.
1493%
1494% o exception: return any errors or warnings in this structure.
1495%
1496*/
1497
cristy7f69b802012-05-08 16:39:59 +00001498static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001499 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001500{
cristy4c08aed2011-07-01 19:47:50 +00001501 MagickBooleanType
1502 status;
1503
cristy3ed852e2009-09-05 21:47:34 +00001504 MagickOffsetType
1505 offset;
1506
cristy73724512010-04-12 14:43:14 +00001507 if (cache_info->type == PingCache)
1508 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001509 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1510 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001511 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001512 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001513 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001514}
1515
cristya6577ff2011-09-02 19:54:26 +00001516MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001517 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001518 NexusInfo *nexus_info,ExceptionInfo *exception)
1519{
1520 CacheInfo
1521 *cache_info;
1522
cristy4c08aed2011-07-01 19:47:50 +00001523 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001524 *q;
cristy3ed852e2009-09-05 21:47:34 +00001525
1526 /*
1527 Transfer pixels from the cache.
1528 */
1529 assert(image != (Image *) NULL);
1530 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001531 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1532 exception);
cristyacd2ed22011-08-30 01:44:23 +00001533 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001534 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001535 cache_info=(CacheInfo *) image->cache;
1536 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001537 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001538 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001539 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001540 return((Quantum *) NULL);
1541 if (cache_info->metacontent_extent != 0)
1542 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1543 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001544 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001545}
1546
1547/*
1548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1549% %
1550% %
1551% %
1552+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1553% %
1554% %
1555% %
1556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1557%
1558% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1559% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1560%
1561% The format of the GetAuthenticPixelsFromCache() method is:
1562%
cristy4c08aed2011-07-01 19:47:50 +00001563% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001564%
1565% A description of each parameter follows:
1566%
1567% o image: the image.
1568%
1569*/
cristy4c08aed2011-07-01 19:47:50 +00001570static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001571{
1572 CacheInfo
1573 *cache_info;
1574
cristy5c9e6f22010-09-17 17:31:01 +00001575 const int
1576 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001577
cristye7cc7cf2010-09-21 13:26:47 +00001578 assert(image != (const Image *) NULL);
1579 assert(image->signature == MagickSignature);
1580 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001581 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001582 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001583 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001584 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001585}
1586
1587/*
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589% %
1590% %
1591% %
1592% G e t A u t h e n t i c P i x e l Q u e u e %
1593% %
1594% %
1595% %
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597%
cristy4c08aed2011-07-01 19:47:50 +00001598% GetAuthenticPixelQueue() returns the authentic pixels associated
1599% corresponding with the last call to QueueAuthenticPixels() or
1600% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001601%
1602% The format of the GetAuthenticPixelQueue() method is:
1603%
cristy4c08aed2011-07-01 19:47:50 +00001604% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001605%
1606% A description of each parameter follows:
1607%
1608% o image: the image.
1609%
1610*/
cristy4c08aed2011-07-01 19:47:50 +00001611MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001612{
1613 CacheInfo
1614 *cache_info;
1615
cristy2036f5c2010-09-19 21:18:17 +00001616 const int
1617 id = GetOpenMPThreadId();
1618
cristy3ed852e2009-09-05 21:47:34 +00001619 assert(image != (const Image *) NULL);
1620 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001621 assert(image->cache != (Cache) NULL);
1622 cache_info=(CacheInfo *) image->cache;
1623 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001624 if (cache_info->methods.get_authentic_pixels_from_handler !=
1625 (GetAuthenticPixelsFromHandler) NULL)
1626 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001627 assert(id < (int) cache_info->number_threads);
1628 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001629}
1630
1631/*
1632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633% %
1634% %
1635% %
1636% G e t A u t h e n t i c P i x e l s %
1637% %
1638% %
cristy4c08aed2011-07-01 19:47:50 +00001639% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001640%
1641% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001642% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001643% representing the region is returned, otherwise NULL is returned.
1644%
1645% The returned pointer may point to a temporary working copy of the pixels
1646% or it may point to the original pixels in memory. Performance is maximized
1647% if the selected region is part of one row, or one or more full rows, since
1648% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001649% if the image is in memory, or in a memory-mapped file. The returned pointer
1650% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001651%
1652% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001653% Quantum. If the image has corresponding metacontent,call
1654% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1655% meta-content corresponding to the region. Once the Quantum array has
1656% been updated, the changes must be saved back to the underlying image using
1657% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001658%
1659% The format of the GetAuthenticPixels() method is:
1660%
cristy4c08aed2011-07-01 19:47:50 +00001661% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001662% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001663% ExceptionInfo *exception)
1664%
1665% A description of each parameter follows:
1666%
1667% o image: the image.
1668%
1669% o x,y,columns,rows: These values define the perimeter of a region of
1670% pixels.
1671%
1672% o exception: return any errors or warnings in this structure.
1673%
1674*/
cristy4c08aed2011-07-01 19:47:50 +00001675MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001676 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001677 ExceptionInfo *exception)
1678{
1679 CacheInfo
1680 *cache_info;
1681
cristy2036f5c2010-09-19 21:18:17 +00001682 const int
1683 id = GetOpenMPThreadId();
1684
cristy4c08aed2011-07-01 19:47:50 +00001685 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001686 *q;
cristy4c08aed2011-07-01 19:47:50 +00001687
cristy3ed852e2009-09-05 21:47:34 +00001688 assert(image != (Image *) NULL);
1689 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001690 assert(image->cache != (Cache) NULL);
1691 cache_info=(CacheInfo *) image->cache;
1692 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001693 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001694 (GetAuthenticPixelsHandler) NULL)
1695 {
cristyacd2ed22011-08-30 01:44:23 +00001696 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1697 exception);
1698 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001699 }
cristy2036f5c2010-09-19 21:18:17 +00001700 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001701 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001702 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001703 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001704}
1705
1706/*
1707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1708% %
1709% %
1710% %
1711+ G e t A u t h e n t i c P i x e l s C a c h e %
1712% %
1713% %
1714% %
1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716%
1717% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1718% as defined by the geometry parameters. A pointer to the pixels is returned
1719% if the pixels are transferred, otherwise a NULL is returned.
1720%
1721% The format of the GetAuthenticPixelsCache() method is:
1722%
cristy4c08aed2011-07-01 19:47:50 +00001723% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001724% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001725% ExceptionInfo *exception)
1726%
1727% A description of each parameter follows:
1728%
1729% o image: the image.
1730%
1731% o x,y,columns,rows: These values define the perimeter of a region of
1732% pixels.
1733%
1734% o exception: return any errors or warnings in this structure.
1735%
1736*/
cristy4c08aed2011-07-01 19:47:50 +00001737static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001738 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001739 ExceptionInfo *exception)
1740{
1741 CacheInfo
1742 *cache_info;
1743
cristy5c9e6f22010-09-17 17:31:01 +00001744 const int
1745 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001746
cristy4c08aed2011-07-01 19:47:50 +00001747 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001748 *q;
cristy4c08aed2011-07-01 19:47:50 +00001749
cristye7cc7cf2010-09-21 13:26:47 +00001750 assert(image != (const Image *) NULL);
1751 assert(image->signature == MagickSignature);
1752 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001753 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001754 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001755 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001756 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001757 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001758 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001759 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001760 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001761}
1762
1763/*
1764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765% %
1766% %
1767% %
1768+ G e t I m a g e E x t e n t %
1769% %
1770% %
1771% %
1772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1773%
cristy4c08aed2011-07-01 19:47:50 +00001774% GetImageExtent() returns the extent of the pixels associated corresponding
1775% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001776%
1777% The format of the GetImageExtent() method is:
1778%
1779% MagickSizeType GetImageExtent(const Image *image)
1780%
1781% A description of each parameter follows:
1782%
1783% o image: the image.
1784%
1785*/
1786MagickExport MagickSizeType GetImageExtent(const Image *image)
1787{
1788 CacheInfo
1789 *cache_info;
1790
cristy5c9e6f22010-09-17 17:31:01 +00001791 const int
1792 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001793
cristy3ed852e2009-09-05 21:47:34 +00001794 assert(image != (Image *) NULL);
1795 assert(image->signature == MagickSignature);
1796 if (image->debug != MagickFalse)
1797 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1798 assert(image->cache != (Cache) NULL);
1799 cache_info=(CacheInfo *) image->cache;
1800 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001801 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001802 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001803}
1804
1805/*
1806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807% %
1808% %
1809% %
1810+ G e t I m a g e P i x e l C a c h e %
1811% %
1812% %
1813% %
1814%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1815%
1816% GetImagePixelCache() ensures that there is only a single reference to the
1817% pixel cache to be modified, updating the provided cache pointer to point to
1818% a clone of the original pixel cache if necessary.
1819%
1820% The format of the GetImagePixelCache method is:
1821%
1822% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1823% ExceptionInfo *exception)
1824%
1825% A description of each parameter follows:
1826%
1827% o image: the image.
1828%
1829% o clone: any value other than MagickFalse clones the cache pixels.
1830%
1831% o exception: return any errors or warnings in this structure.
1832%
1833*/
cristyaf894d72011-08-06 23:03:10 +00001834
cristyf1832792012-05-08 18:38:18 +00001835static inline MagickBooleanType ValidatePixelCacheMorphology(
1836 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001837{
cristyf1832792012-05-08 18:38:18 +00001838 const CacheInfo
1839 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001840
cristyf1832792012-05-08 18:38:18 +00001841 const PixelChannelMap
1842 *restrict p,
1843 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001844
cristy3ed852e2009-09-05 21:47:34 +00001845 /*
1846 Does the image match the pixel cache morphology?
1847 */
1848 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001849 p=image->channel_map;
1850 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001851 if ((image->storage_class != cache_info->storage_class) ||
1852 (image->colorspace != cache_info->colorspace) ||
cristy8a46d822012-08-28 23:32:39 +00001853 (image->alpha_trait != cache_info->alpha_trait) ||
cristy183a5c72012-01-30 01:40:35 +00001854 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001855 (image->columns != cache_info->columns) ||
1856 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001857 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001858 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001859 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001860 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001861 return(MagickFalse);
1862 return(MagickTrue);
1863}
1864
cristycd01fae2011-08-06 23:52:42 +00001865static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1866 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001867{
1868 CacheInfo
1869 *cache_info;
1870
cristy3ed852e2009-09-05 21:47:34 +00001871 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001872 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001873 status;
1874
cristy50a10922010-02-15 18:35:25 +00001875 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001876 cpu_throttle = 0,
1877 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001878 time_limit = 0;
1879
cristy1ea34962010-07-01 19:49:21 +00001880 static time_t
cristy208b1002011-08-07 18:51:50 +00001881 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001882
cristyc4f9f132010-03-04 18:50:01 +00001883 status=MagickTrue;
1884 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001885 if (cpu_throttle == 0)
1886 {
1887 char
1888 *limit;
1889
1890 /*
1891 Set CPU throttle in milleseconds.
1892 */
1893 cpu_throttle=MagickResourceInfinity;
1894 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1895 if (limit == (char *) NULL)
1896 limit=GetPolicyValue("throttle");
1897 if (limit != (char *) NULL)
1898 {
1899 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1900 limit=DestroyString(limit);
1901 }
1902 }
1903 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1904 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001905 if (time_limit == 0)
1906 {
cristy6ebe97c2010-07-03 01:17:28 +00001907 /*
1908 Set the exire time in seconds.
1909 */
cristy1ea34962010-07-01 19:49:21 +00001910 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001911 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001912 }
1913 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001914 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001915 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001916 assert(image->cache != (Cache) NULL);
1917 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001918 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001919 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001920 {
cristyceb55ee2010-11-06 16:05:49 +00001921 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001922 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001923 {
cristyceb55ee2010-11-06 16:05:49 +00001924 Image
1925 clone_image;
1926
1927 CacheInfo
1928 *clone_info;
1929
1930 /*
1931 Clone pixel cache.
1932 */
1933 clone_image=(*image);
1934 clone_image.semaphore=AllocateSemaphoreInfo();
1935 clone_image.reference_count=1;
1936 clone_image.cache=ClonePixelCache(cache_info);
1937 clone_info=(CacheInfo *) clone_image.cache;
1938 status=OpenPixelCache(&clone_image,IOMode,exception);
1939 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001940 {
cristy5a7fbfb2010-11-06 16:10:59 +00001941 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001942 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001943 if (status != MagickFalse)
1944 {
cristy979bf772011-08-08 00:04:15 +00001945 if (cache_info->mode == ReadMode)
1946 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001947 destroy=MagickTrue;
1948 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001949 }
1950 }
cristyceb55ee2010-11-06 16:05:49 +00001951 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001952 }
cristyceb55ee2010-11-06 16:05:49 +00001953 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001954 }
cristy4320e0e2009-09-10 15:00:08 +00001955 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001956 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001957 if (status != MagickFalse)
1958 {
1959 /*
1960 Ensure the image matches the pixel cache morphology.
1961 */
1962 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001963 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001964 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001965 {
1966 status=OpenPixelCache(image,IOMode,exception);
1967 cache_info=(CacheInfo *) image->cache;
1968 if (cache_info->type == DiskCache)
1969 (void) ClosePixelCacheOnDisk(cache_info);
1970 }
cristy3ed852e2009-09-05 21:47:34 +00001971 }
cristyf84a1932010-01-03 18:00:18 +00001972 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001973 if (status == MagickFalse)
1974 return((Cache) NULL);
1975 return(image->cache);
1976}
1977
1978/*
1979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980% %
1981% %
1982% %
cristyce1fe792012-05-16 15:58:37 +00001983+ G e t I m a g e P i x e l C a c h e T y p e %
1984% %
1985% %
1986% %
1987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988%
1989% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1990% DiskCache, MemoryCache, MapCache, or PingCache.
1991%
1992% The format of the GetImagePixelCacheType() method is:
1993%
cristy5bef4cd2012-05-17 18:08:56 +00001994% CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001995%
1996% A description of each parameter follows:
1997%
1998% o image: the image.
1999%
2000*/
cristy5bef4cd2012-05-17 18:08:56 +00002001MagickExport CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00002002{
cristy238287d2012-05-17 18:16:56 +00002003 CacheInfo
2004 *cache_info;
2005
2006 assert(image != (Image *) NULL);
2007 assert(image->signature == MagickSignature);
2008 assert(image->cache != (Cache) NULL);
2009 cache_info=(CacheInfo *) image->cache;
2010 assert(cache_info->signature == MagickSignature);
2011 return(cache_info->type);
cristyce1fe792012-05-16 15:58:37 +00002012}
2013
2014/*
2015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2016% %
2017% %
2018% %
cristy3ed852e2009-09-05 21:47:34 +00002019% G e t O n e A u t h e n t i c P i x e l %
2020% %
2021% %
2022% %
2023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2024%
2025% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2026% location. The image background color is returned if an error occurs.
2027%
2028% The format of the GetOneAuthenticPixel() method is:
2029%
cristybb503372010-05-27 20:51:26 +00002030% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002031% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002032%
2033% A description of each parameter follows:
2034%
2035% o image: the image.
2036%
2037% o x,y: These values define the location of the pixel to return.
2038%
2039% o pixel: return a pixel at the specified (x,y) location.
2040%
2041% o exception: return any errors or warnings in this structure.
2042%
2043*/
cristyacbbb7c2010-06-30 18:56:48 +00002044MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002045 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002046{
2047 CacheInfo
2048 *cache_info;
2049
cristy4c08aed2011-07-01 19:47:50 +00002050 register Quantum
2051 *q;
cristy2036f5c2010-09-19 21:18:17 +00002052
cristy2ed42f62011-10-02 19:49:57 +00002053 register ssize_t
2054 i;
2055
cristy3ed852e2009-09-05 21:47:34 +00002056 assert(image != (Image *) NULL);
2057 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002058 assert(image->cache != (Cache) NULL);
2059 cache_info=(CacheInfo *) image->cache;
2060 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002061 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002062 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2063 (GetOneAuthenticPixelFromHandler) NULL)
2064 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2065 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002066 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2067 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002068 {
cristy9e0719b2011-12-29 03:45:45 +00002069 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2070 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2071 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2072 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2073 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002074 return(MagickFalse);
2075 }
2076 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2077 {
2078 PixelChannel
2079 channel;
2080
cristycf1296e2012-08-26 23:40:49 +00002081 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002082 pixel[channel]=q[i];
2083 }
cristy2036f5c2010-09-19 21:18:17 +00002084 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002085}
2086
2087/*
2088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2089% %
2090% %
2091% %
2092+ G e t O n e A u t h e n t i c P i x e l F r o m C a c h e %
2093% %
2094% %
2095% %
2096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2097%
2098% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2099% location. The image background color is returned if an error occurs.
2100%
2101% The format of the GetOneAuthenticPixelFromCache() method is:
2102%
2103% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002104% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002105% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002106%
2107% A description of each parameter follows:
2108%
2109% o image: the image.
2110%
2111% o x,y: These values define the location of the pixel to return.
2112%
2113% o pixel: return a pixel at the specified (x,y) location.
2114%
2115% o exception: return any errors or warnings in this structure.
2116%
2117*/
2118static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002119 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002120{
cristy098f78c2010-09-23 17:28:44 +00002121 CacheInfo
2122 *cache_info;
2123
2124 const int
2125 id = GetOpenMPThreadId();
2126
cristy4c08aed2011-07-01 19:47:50 +00002127 register Quantum
2128 *q;
cristy3ed852e2009-09-05 21:47:34 +00002129
cristy2ed42f62011-10-02 19:49:57 +00002130 register ssize_t
2131 i;
2132
cristy0158a4b2010-09-20 13:59:45 +00002133 assert(image != (const Image *) NULL);
2134 assert(image->signature == MagickSignature);
2135 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002136 cache_info=(CacheInfo *) image->cache;
2137 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002138 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002139 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002140 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2141 exception);
2142 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002143 {
cristy9e0719b2011-12-29 03:45:45 +00002144 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2145 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2146 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2147 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2148 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002149 return(MagickFalse);
2150 }
2151 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2152 {
2153 PixelChannel
2154 channel;
2155
cristycf1296e2012-08-26 23:40:49 +00002156 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002157 pixel[channel]=q[i];
2158 }
cristy3ed852e2009-09-05 21:47:34 +00002159 return(MagickTrue);
2160}
2161
2162/*
2163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164% %
2165% %
2166% %
cristy3ed852e2009-09-05 21:47:34 +00002167% G e t O n e V i r t u a l P i x e l %
2168% %
2169% %
2170% %
2171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2172%
2173% GetOneVirtualPixel() returns a single virtual pixel at the specified
2174% (x,y) location. The image background color is returned if an error occurs.
2175% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2176%
2177% The format of the GetOneVirtualPixel() method is:
2178%
cristybb503372010-05-27 20:51:26 +00002179% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002180% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002181%
2182% A description of each parameter follows:
2183%
2184% o image: the image.
2185%
2186% o x,y: These values define the location of the pixel to return.
2187%
2188% o pixel: return a pixel at the specified (x,y) location.
2189%
2190% o exception: return any errors or warnings in this structure.
2191%
2192*/
2193MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002194 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002195{
cristy3ed852e2009-09-05 21:47:34 +00002196 CacheInfo
2197 *cache_info;
2198
cristy0158a4b2010-09-20 13:59:45 +00002199 const int
2200 id = GetOpenMPThreadId();
2201
cristy4c08aed2011-07-01 19:47:50 +00002202 const Quantum
2203 *p;
cristy2036f5c2010-09-19 21:18:17 +00002204
cristy2ed42f62011-10-02 19:49:57 +00002205 register ssize_t
2206 i;
2207
cristy3ed852e2009-09-05 21:47:34 +00002208 assert(image != (const Image *) NULL);
2209 assert(image->signature == MagickSignature);
2210 assert(image->cache != (Cache) NULL);
2211 cache_info=(CacheInfo *) image->cache;
2212 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002213 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002214 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2215 (GetOneVirtualPixelFromHandler) NULL)
2216 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2217 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002218 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002219 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002220 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002221 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002222 {
cristy9e0719b2011-12-29 03:45:45 +00002223 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2224 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2225 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2226 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2227 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002228 return(MagickFalse);
2229 }
2230 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2231 {
2232 PixelChannel
2233 channel;
2234
cristycf1296e2012-08-26 23:40:49 +00002235 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002236 pixel[channel]=p[i];
2237 }
cristy2036f5c2010-09-19 21:18:17 +00002238 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002239}
2240
2241/*
2242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243% %
2244% %
2245% %
2246+ G e t O n e V i r t u a l P i x e l F r o m C a c h e %
2247% %
2248% %
2249% %
2250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2251%
2252% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2253% specified (x,y) location. The image background color is returned if an
2254% error occurs.
2255%
2256% The format of the GetOneVirtualPixelFromCache() method is:
2257%
2258% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002259% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002260% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002261%
2262% A description of each parameter follows:
2263%
2264% o image: the image.
2265%
2266% o virtual_pixel_method: the virtual pixel method.
2267%
2268% o x,y: These values define the location of the pixel to return.
2269%
2270% o pixel: return a pixel at the specified (x,y) location.
2271%
2272% o exception: return any errors or warnings in this structure.
2273%
2274*/
2275static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002276 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002277 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002278{
cristy0158a4b2010-09-20 13:59:45 +00002279 CacheInfo
2280 *cache_info;
2281
2282 const int
2283 id = GetOpenMPThreadId();
2284
cristy4c08aed2011-07-01 19:47:50 +00002285 const Quantum
2286 *p;
cristy3ed852e2009-09-05 21:47:34 +00002287
cristy2ed42f62011-10-02 19:49:57 +00002288 register ssize_t
2289 i;
2290
cristye7cc7cf2010-09-21 13:26:47 +00002291 assert(image != (const Image *) NULL);
2292 assert(image->signature == MagickSignature);
2293 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002294 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002295 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002296 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002297 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002298 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002299 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002300 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002301 {
cristy9e0719b2011-12-29 03:45:45 +00002302 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2303 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2304 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2305 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2306 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002307 return(MagickFalse);
2308 }
2309 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2310 {
2311 PixelChannel
2312 channel;
2313
cristycf1296e2012-08-26 23:40:49 +00002314 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002315 pixel[channel]=p[i];
2316 }
cristy3ed852e2009-09-05 21:47:34 +00002317 return(MagickTrue);
2318}
2319
2320/*
2321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2322% %
2323% %
2324% %
cristy3aa93752011-12-18 15:54:24 +00002325% G e t O n e V i r t u a l P i x e l I n f o %
2326% %
2327% %
2328% %
2329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2330%
2331% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2332% location. The image background color is returned if an error occurs. If
2333% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2334%
2335% The format of the GetOneVirtualPixelInfo() method is:
2336%
2337% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2338% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2339% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2340%
2341% A description of each parameter follows:
2342%
2343% o image: the image.
2344%
2345% o virtual_pixel_method: the virtual pixel method.
2346%
2347% o x,y: these values define the location of the pixel to return.
2348%
2349% o pixel: return a pixel at the specified (x,y) location.
2350%
2351% o exception: return any errors or warnings in this structure.
2352%
2353*/
2354MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2355 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2356 PixelInfo *pixel,ExceptionInfo *exception)
2357{
2358 CacheInfo
2359 *cache_info;
2360
2361 const int
2362 id = GetOpenMPThreadId();
2363
2364 register const Quantum
2365 *p;
2366
2367 assert(image != (const Image *) NULL);
2368 assert(image->signature == MagickSignature);
2369 assert(image->cache != (Cache) NULL);
2370 cache_info=(CacheInfo *) image->cache;
2371 assert(cache_info->signature == MagickSignature);
2372 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002373 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002374 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2375 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002376 if (p == (const Quantum *) NULL)
2377 return(MagickFalse);
2378 GetPixelInfoPixel(image,p,pixel);
2379 return(MagickTrue);
2380}
2381
2382/*
2383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2384% %
2385% %
2386% %
cristy3ed852e2009-09-05 21:47:34 +00002387+ G e t P i x e l C a c h e C o l o r s p a c e %
2388% %
2389% %
2390% %
2391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2392%
2393% GetPixelCacheColorspace() returns the class type of the pixel cache.
2394%
2395% The format of the GetPixelCacheColorspace() method is:
2396%
2397% Colorspace GetPixelCacheColorspace(Cache cache)
2398%
2399% A description of each parameter follows:
2400%
2401% o cache: the pixel cache.
2402%
2403*/
cristya6577ff2011-09-02 19:54:26 +00002404MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002405{
2406 CacheInfo
2407 *cache_info;
2408
2409 assert(cache != (Cache) NULL);
2410 cache_info=(CacheInfo *) cache;
2411 assert(cache_info->signature == MagickSignature);
2412 if (cache_info->debug != MagickFalse)
2413 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2414 cache_info->filename);
2415 return(cache_info->colorspace);
2416}
2417
2418/*
2419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2420% %
2421% %
2422% %
2423+ G e t P i x e l C a c h e M e t h o d s %
2424% %
2425% %
2426% %
2427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2428%
2429% GetPixelCacheMethods() initializes the CacheMethods structure.
2430%
2431% The format of the GetPixelCacheMethods() method is:
2432%
2433% void GetPixelCacheMethods(CacheMethods *cache_methods)
2434%
2435% A description of each parameter follows:
2436%
2437% o cache_methods: Specifies a pointer to a CacheMethods structure.
2438%
2439*/
cristya6577ff2011-09-02 19:54:26 +00002440MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002441{
2442 assert(cache_methods != (CacheMethods *) NULL);
2443 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2444 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2445 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002446 cache_methods->get_virtual_metacontent_from_handler=
2447 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002448 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2449 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002450 cache_methods->get_authentic_metacontent_from_handler=
2451 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002452 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2453 cache_methods->get_one_authentic_pixel_from_handler=
2454 GetOneAuthenticPixelFromCache;
2455 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2456 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2457 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2458}
2459
2460/*
2461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462% %
2463% %
2464% %
2465+ G e t P i x e l C a c h e N e x u s E x t e n t %
2466% %
2467% %
2468% %
2469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2470%
cristy4c08aed2011-07-01 19:47:50 +00002471% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2472% corresponding with the last call to SetPixelCacheNexusPixels() or
2473% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002474%
2475% The format of the GetPixelCacheNexusExtent() method is:
2476%
2477% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2478% NexusInfo *nexus_info)
2479%
2480% A description of each parameter follows:
2481%
2482% o nexus_info: the nexus info.
2483%
2484*/
cristya6577ff2011-09-02 19:54:26 +00002485MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002486 NexusInfo *nexus_info)
2487{
2488 CacheInfo
2489 *cache_info;
2490
2491 MagickSizeType
2492 extent;
2493
cristy9f027d12011-09-21 01:17:17 +00002494 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002495 cache_info=(CacheInfo *) cache;
2496 assert(cache_info->signature == MagickSignature);
2497 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2498 if (extent == 0)
2499 return((MagickSizeType) cache_info->columns*cache_info->rows);
2500 return(extent);
2501}
2502
2503/*
2504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2505% %
2506% %
2507% %
cristy4c08aed2011-07-01 19:47:50 +00002508+ G e t P i x e l C a c h e N e x u s M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002509% %
2510% %
2511% %
2512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2513%
cristy4c08aed2011-07-01 19:47:50 +00002514% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2515% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002516%
cristy4c08aed2011-07-01 19:47:50 +00002517% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002518%
cristy4c08aed2011-07-01 19:47:50 +00002519% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002520% NexusInfo *nexus_info)
2521%
2522% A description of each parameter follows:
2523%
2524% o cache: the pixel cache.
2525%
cristy4c08aed2011-07-01 19:47:50 +00002526% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002527%
2528*/
cristya6577ff2011-09-02 19:54:26 +00002529MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002530 NexusInfo *nexus_info)
2531{
2532 CacheInfo
2533 *cache_info;
2534
cristy9f027d12011-09-21 01:17:17 +00002535 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002536 cache_info=(CacheInfo *) cache;
2537 assert(cache_info->signature == MagickSignature);
2538 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002539 return((void *) NULL);
2540 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002541}
2542
2543/*
2544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2545% %
2546% %
2547% %
2548+ G e t P i x e l C a c h e N e x u s P i x e l s %
2549% %
2550% %
2551% %
2552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2553%
2554% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2555% cache nexus.
2556%
2557% The format of the GetPixelCacheNexusPixels() method is:
2558%
cristy4c08aed2011-07-01 19:47:50 +00002559% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002560% NexusInfo *nexus_info)
2561%
2562% A description of each parameter follows:
2563%
2564% o cache: the pixel cache.
2565%
2566% o nexus_info: the cache nexus to return the pixels.
2567%
2568*/
cristya6577ff2011-09-02 19:54:26 +00002569MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002570 NexusInfo *nexus_info)
2571{
2572 CacheInfo
2573 *cache_info;
2574
cristy9f027d12011-09-21 01:17:17 +00002575 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002576 cache_info=(CacheInfo *) cache;
2577 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002578 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002579 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002580 return(nexus_info->pixels);
2581}
2582
2583/*
2584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585% %
2586% %
2587% %
cristy056ba772010-01-02 23:33:54 +00002588+ G e t P i x e l C a c h e P i x e l s %
2589% %
2590% %
2591% %
2592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2593%
2594% GetPixelCachePixels() returns the pixels associated with the specified image.
2595%
2596% The format of the GetPixelCachePixels() method is:
2597%
cristyf84a1932010-01-03 18:00:18 +00002598% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2599% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002600%
2601% A description of each parameter follows:
2602%
2603% o image: the image.
2604%
2605% o length: the pixel cache length.
2606%
cristyf84a1932010-01-03 18:00:18 +00002607% o exception: return any errors or warnings in this structure.
2608%
cristy056ba772010-01-02 23:33:54 +00002609*/
cristyd1dd6e42011-09-04 01:46:08 +00002610MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002611 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002612{
2613 CacheInfo
2614 *cache_info;
2615
2616 assert(image != (const Image *) NULL);
2617 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002618 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002619 assert(length != (MagickSizeType *) NULL);
2620 assert(exception != (ExceptionInfo *) NULL);
2621 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002622 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002623 assert(cache_info->signature == MagickSignature);
2624 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002625 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002626 return((void *) NULL);
2627 *length=cache_info->length;
2628 return((void *) cache_info->pixels);
2629}
2630
2631/*
2632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633% %
2634% %
2635% %
cristyb32b90a2009-09-07 21:45:48 +00002636+ G e t P i x e l C a c h e S t o r a g e C l a s s %
cristy3ed852e2009-09-05 21:47:34 +00002637% %
2638% %
2639% %
2640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2641%
2642% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2643%
2644% The format of the GetPixelCacheStorageClass() method is:
2645%
2646% ClassType GetPixelCacheStorageClass(Cache cache)
2647%
2648% A description of each parameter follows:
2649%
2650% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2651%
2652% o cache: the pixel cache.
2653%
2654*/
cristya6577ff2011-09-02 19:54:26 +00002655MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002656{
2657 CacheInfo
2658 *cache_info;
2659
2660 assert(cache != (Cache) NULL);
2661 cache_info=(CacheInfo *) cache;
2662 assert(cache_info->signature == MagickSignature);
2663 if (cache_info->debug != MagickFalse)
2664 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2665 cache_info->filename);
2666 return(cache_info->storage_class);
2667}
2668
2669/*
2670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671% %
2672% %
2673% %
cristyb32b90a2009-09-07 21:45:48 +00002674+ G e t P i x e l C a c h e T i l e S i z e %
2675% %
2676% %
2677% %
2678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2679%
2680% GetPixelCacheTileSize() returns the pixel cache tile size.
2681%
2682% The format of the GetPixelCacheTileSize() method is:
2683%
cristybb503372010-05-27 20:51:26 +00002684% void GetPixelCacheTileSize(const Image *image,size_t *width,
2685% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002686%
2687% A description of each parameter follows:
2688%
2689% o image: the image.
2690%
2691% o width: the optimize cache tile width in pixels.
2692%
2693% o height: the optimize cache tile height in pixels.
2694%
2695*/
cristya6577ff2011-09-02 19:54:26 +00002696MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002697 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002698{
cristy4c08aed2011-07-01 19:47:50 +00002699 CacheInfo
2700 *cache_info;
2701
cristyb32b90a2009-09-07 21:45:48 +00002702 assert(image != (Image *) NULL);
2703 assert(image->signature == MagickSignature);
2704 if (image->debug != MagickFalse)
2705 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002706 cache_info=(CacheInfo *) image->cache;
2707 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002708 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristy238287d2012-05-17 18:16:56 +00002709 if (GetImagePixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002710 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002711 *height=(*width);
2712}
2713
2714/*
2715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716% %
2717% %
2718% %
cristy3ed852e2009-09-05 21:47:34 +00002719+ G e t P i x e l C a c h e V i r t u a l M e t h o d %
2720% %
2721% %
2722% %
2723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2724%
2725% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2726% pixel cache. A virtual pixel is any pixel access that is outside the
2727% boundaries of the image cache.
2728%
2729% The format of the GetPixelCacheVirtualMethod() method is:
2730%
2731% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2732%
2733% A description of each parameter follows:
2734%
2735% o image: the image.
2736%
2737*/
cristyd1dd6e42011-09-04 01:46:08 +00002738MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002739{
2740 CacheInfo
2741 *cache_info;
2742
2743 assert(image != (Image *) NULL);
2744 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002745 assert(image->cache != (Cache) NULL);
2746 cache_info=(CacheInfo *) image->cache;
2747 assert(cache_info->signature == MagickSignature);
2748 return(cache_info->virtual_pixel_method);
2749}
2750
2751/*
2752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2753% %
2754% %
2755% %
cristy4c08aed2011-07-01 19:47:50 +00002756+ G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00002757% %
2758% %
2759% %
2760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2761%
cristy4c08aed2011-07-01 19:47:50 +00002762% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2763% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002764%
cristy4c08aed2011-07-01 19:47:50 +00002765% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002766%
cristy4c08aed2011-07-01 19:47:50 +00002767% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002768%
2769% A description of each parameter follows:
2770%
2771% o image: the image.
2772%
2773*/
cristy4c08aed2011-07-01 19:47:50 +00002774static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002775{
2776 CacheInfo
2777 *cache_info;
2778
cristy5c9e6f22010-09-17 17:31:01 +00002779 const int
2780 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002781
cristy4c08aed2011-07-01 19:47:50 +00002782 const void
2783 *metacontent;
2784
cristye7cc7cf2010-09-21 13:26:47 +00002785 assert(image != (const Image *) NULL);
2786 assert(image->signature == MagickSignature);
2787 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002788 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002789 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002790 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002791 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2792 cache_info->nexus_info[id]);
2793 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002794}
2795
2796/*
2797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2798% %
2799% %
2800% %
cristy4c08aed2011-07-01 19:47:50 +00002801+ G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00002802% %
2803% %
2804% %
2805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2806%
cristy4c08aed2011-07-01 19:47:50 +00002807% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2808% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002809%
cristy4c08aed2011-07-01 19:47:50 +00002810% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002811%
cristy4c08aed2011-07-01 19:47:50 +00002812% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002813% NexusInfo *nexus_info)
2814%
2815% A description of each parameter follows:
2816%
2817% o cache: the pixel cache.
2818%
cristy4c08aed2011-07-01 19:47:50 +00002819% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002820%
2821*/
cristya6577ff2011-09-02 19:54:26 +00002822MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002823 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002824{
2825 CacheInfo
2826 *cache_info;
2827
cristye7cc7cf2010-09-21 13:26:47 +00002828 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002829 cache_info=(CacheInfo *) cache;
2830 assert(cache_info->signature == MagickSignature);
2831 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002832 return((void *) NULL);
2833 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002834}
2835
2836/*
2837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838% %
2839% %
2840% %
cristy4c08aed2011-07-01 19:47:50 +00002841% G e t V i r t u a l M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002842% %
2843% %
2844% %
2845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2846%
cristy4c08aed2011-07-01 19:47:50 +00002847% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2848% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2849% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002850%
cristy4c08aed2011-07-01 19:47:50 +00002851% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002852%
cristy4c08aed2011-07-01 19:47:50 +00002853% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002854%
2855% A description of each parameter follows:
2856%
2857% o image: the image.
2858%
2859*/
cristy4c08aed2011-07-01 19:47:50 +00002860MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002861{
2862 CacheInfo
2863 *cache_info;
2864
cristy2036f5c2010-09-19 21:18:17 +00002865 const int
2866 id = GetOpenMPThreadId();
2867
cristy4c08aed2011-07-01 19:47:50 +00002868 const void
2869 *metacontent;
2870
cristy3ed852e2009-09-05 21:47:34 +00002871 assert(image != (const Image *) NULL);
2872 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002873 assert(image->cache != (Cache) NULL);
2874 cache_info=(CacheInfo *) image->cache;
2875 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002876 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002877 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002878 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002879 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002880 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2881 cache_info->nexus_info[id]);
2882 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002883}
2884
2885/*
2886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2887% %
2888% %
2889% %
2890+ G e t V i r t u a l P i x e l s F r o m N e x u s %
2891% %
2892% %
2893% %
2894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2895%
2896% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2897% pixel cache as defined by the geometry parameters. A pointer to the pixels
2898% is returned if the pixels are transferred, otherwise a NULL is returned.
2899%
2900% The format of the GetVirtualPixelsFromNexus() method is:
2901%
cristy4c08aed2011-07-01 19:47:50 +00002902% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002903% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002904% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2905% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002906%
2907% A description of each parameter follows:
2908%
2909% o image: the image.
2910%
2911% o virtual_pixel_method: the virtual pixel method.
2912%
2913% o x,y,columns,rows: These values define the perimeter of a region of
2914% pixels.
2915%
2916% o nexus_info: the cache nexus to acquire.
2917%
2918% o exception: return any errors or warnings in this structure.
2919%
2920*/
2921
cristybb503372010-05-27 20:51:26 +00002922static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002923 DitherMatrix[64] =
2924 {
2925 0, 48, 12, 60, 3, 51, 15, 63,
2926 32, 16, 44, 28, 35, 19, 47, 31,
2927 8, 56, 4, 52, 11, 59, 7, 55,
2928 40, 24, 36, 20, 43, 27, 39, 23,
2929 2, 50, 14, 62, 1, 49, 13, 61,
2930 34, 18, 46, 30, 33, 17, 45, 29,
2931 10, 58, 6, 54, 9, 57, 5, 53,
2932 42, 26, 38, 22, 41, 25, 37, 21
2933 };
2934
cristybb503372010-05-27 20:51:26 +00002935static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002936{
cristybb503372010-05-27 20:51:26 +00002937 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002938 index;
2939
2940 index=x+DitherMatrix[x & 0x07]-32L;
2941 if (index < 0L)
2942 return(0L);
cristybb503372010-05-27 20:51:26 +00002943 if (index >= (ssize_t) columns)
2944 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002945 return(index);
2946}
2947
cristybb503372010-05-27 20:51:26 +00002948static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002949{
cristybb503372010-05-27 20:51:26 +00002950 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002951 index;
2952
2953 index=y+DitherMatrix[y & 0x07]-32L;
2954 if (index < 0L)
2955 return(0L);
cristybb503372010-05-27 20:51:26 +00002956 if (index >= (ssize_t) rows)
2957 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002958 return(index);
2959}
2960
cristybb503372010-05-27 20:51:26 +00002961static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002962{
2963 if (x < 0L)
2964 return(0L);
cristybb503372010-05-27 20:51:26 +00002965 if (x >= (ssize_t) columns)
2966 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002967 return(x);
2968}
2969
cristybb503372010-05-27 20:51:26 +00002970static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002971{
2972 if (y < 0L)
2973 return(0L);
cristybb503372010-05-27 20:51:26 +00002974 if (y >= (ssize_t) rows)
2975 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002976 return(y);
2977}
2978
cristybb503372010-05-27 20:51:26 +00002979static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002980{
cristybb503372010-05-27 20:51:26 +00002981 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002982}
2983
cristybb503372010-05-27 20:51:26 +00002984static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002985{
cristybb503372010-05-27 20:51:26 +00002986 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002987}
2988
cristybb503372010-05-27 20:51:26 +00002989static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2990 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002991{
2992 MagickModulo
2993 modulo;
2994
cristy6162bb42011-07-18 11:34:09 +00002995 /*
2996 Compute the remainder of dividing offset by extent. It returns not only
2997 the quotient (tile the offset falls in) but also the positive remainer
2998 within that tile such that 0 <= remainder < extent. This method is
2999 essentially a ldiv() using a floored modulo division rather than the
3000 normal default truncated modulo division.
3001 */
cristybb503372010-05-27 20:51:26 +00003002 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003003 if (offset < 0L)
3004 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003005 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003006 return(modulo);
3007}
3008
cristya6577ff2011-09-02 19:54:26 +00003009MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003010 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3011 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003012 ExceptionInfo *exception)
3013{
3014 CacheInfo
3015 *cache_info;
3016
3017 MagickOffsetType
3018 offset;
3019
3020 MagickSizeType
3021 length,
3022 number_pixels;
3023
3024 NexusInfo
3025 **virtual_nexus;
3026
cristy4c08aed2011-07-01 19:47:50 +00003027 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003028 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003029 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003030
3031 RectangleInfo
3032 region;
3033
cristy4c08aed2011-07-01 19:47:50 +00003034 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003035 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003036
cristy4c08aed2011-07-01 19:47:50 +00003037 register const void
3038 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003039
cristy4c08aed2011-07-01 19:47:50 +00003040 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003041 *restrict q;
3042
cristybb503372010-05-27 20:51:26 +00003043 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003044 i,
3045 u;
cristy3ed852e2009-09-05 21:47:34 +00003046
cristy4c08aed2011-07-01 19:47:50 +00003047 register unsigned char
3048 *restrict s;
3049
cristy105ba3c2011-07-18 02:28:38 +00003050 ssize_t
3051 v;
3052
cristy4c08aed2011-07-01 19:47:50 +00003053 void
cristy105ba3c2011-07-18 02:28:38 +00003054 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003055
cristy3ed852e2009-09-05 21:47:34 +00003056 /*
3057 Acquire pixels.
3058 */
cristye7cc7cf2010-09-21 13:26:47 +00003059 assert(image != (const Image *) NULL);
3060 assert(image->signature == MagickSignature);
3061 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003062 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003063 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003064 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003065 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003066 region.x=x;
3067 region.y=y;
3068 region.width=columns;
3069 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003070 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003071 if (pixels == (Quantum *) NULL)
3072 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003073 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003074 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3075 nexus_info->region.x;
3076 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3077 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003078 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3079 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003080 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3081 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003082 {
3083 MagickBooleanType
3084 status;
3085
3086 /*
3087 Pixel request is inside cache extents.
3088 */
cristy4c08aed2011-07-01 19:47:50 +00003089 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003090 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003091 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3092 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003093 return((const Quantum *) NULL);
3094 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003095 {
cristy4c08aed2011-07-01 19:47:50 +00003096 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003097 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003098 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003099 }
cristyacd2ed22011-08-30 01:44:23 +00003100 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003101 }
3102 /*
3103 Pixel request is outside cache extents.
3104 */
cristy4c08aed2011-07-01 19:47:50 +00003105 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003106 virtual_nexus=AcquirePixelCacheNexus(1);
3107 if (virtual_nexus == (NexusInfo **) NULL)
3108 {
cristy4c08aed2011-07-01 19:47:50 +00003109 if (virtual_nexus != (NexusInfo **) NULL)
3110 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003111 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003112 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003113 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003114 }
cristy105ba3c2011-07-18 02:28:38 +00003115 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3116 sizeof(*virtual_pixel));
3117 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003118 switch (virtual_pixel_method)
3119 {
cristy4c08aed2011-07-01 19:47:50 +00003120 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003121 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003122 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003123 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003124 case MaskVirtualPixelMethod:
3125 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003126 case EdgeVirtualPixelMethod:
3127 case CheckerTileVirtualPixelMethod:
3128 case HorizontalTileVirtualPixelMethod:
3129 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003130 {
cristy4c08aed2011-07-01 19:47:50 +00003131 if (cache_info->metacontent_extent != 0)
3132 {
cristy6162bb42011-07-18 11:34:09 +00003133 /*
3134 Acquire a metacontent buffer.
3135 */
cristya64b85d2011-09-14 01:02:31 +00003136 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003137 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003138 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003139 {
cristy4c08aed2011-07-01 19:47:50 +00003140 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3141 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003142 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003143 return((const Quantum *) NULL);
3144 }
cristy105ba3c2011-07-18 02:28:38 +00003145 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003146 cache_info->metacontent_extent);
3147 }
3148 switch (virtual_pixel_method)
3149 {
3150 case BlackVirtualPixelMethod:
3151 {
cristy30301712011-07-18 15:06:51 +00003152 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3153 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003154 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3155 break;
3156 }
3157 case GrayVirtualPixelMethod:
3158 {
cristy30301712011-07-18 15:06:51 +00003159 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003160 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3161 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003162 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3163 break;
3164 }
3165 case TransparentVirtualPixelMethod:
3166 {
cristy30301712011-07-18 15:06:51 +00003167 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3168 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003169 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3170 break;
3171 }
3172 case MaskVirtualPixelMethod:
3173 case WhiteVirtualPixelMethod:
3174 {
cristy30301712011-07-18 15:06:51 +00003175 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3176 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003177 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3178 break;
3179 }
3180 default:
3181 {
cristy9e0719b2011-12-29 03:45:45 +00003182 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3183 virtual_pixel);
3184 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3185 virtual_pixel);
3186 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3187 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003188 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3189 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003190 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3191 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003192 break;
3193 }
3194 }
cristy3ed852e2009-09-05 21:47:34 +00003195 break;
3196 }
3197 default:
cristy3ed852e2009-09-05 21:47:34 +00003198 break;
cristy3ed852e2009-09-05 21:47:34 +00003199 }
cristybb503372010-05-27 20:51:26 +00003200 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003201 {
cristybb503372010-05-27 20:51:26 +00003202 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003203 {
3204 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003205 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003206 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3207 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003208 {
3209 MagickModulo
3210 x_modulo,
3211 y_modulo;
3212
3213 /*
3214 Transfer a single pixel.
3215 */
3216 length=(MagickSizeType) 1;
3217 switch (virtual_pixel_method)
3218 {
cristy3ed852e2009-09-05 21:47:34 +00003219 default:
3220 {
3221 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003222 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003223 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003224 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003225 break;
3226 }
3227 case RandomVirtualPixelMethod:
3228 {
3229 if (cache_info->random_info == (RandomInfo *) NULL)
3230 cache_info->random_info=AcquireRandomInfo();
3231 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003232 RandomX(cache_info->random_info,cache_info->columns),
3233 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003234 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003235 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003236 break;
3237 }
3238 case DitherVirtualPixelMethod:
3239 {
3240 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003241 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003242 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003243 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003244 break;
3245 }
3246 case TileVirtualPixelMethod:
3247 {
3248 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3249 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3250 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003251 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003252 exception);
cristy4c08aed2011-07-01 19:47:50 +00003253 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003254 break;
3255 }
3256 case MirrorVirtualPixelMethod:
3257 {
3258 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3259 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003260 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003261 x_modulo.remainder-1L;
3262 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3263 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003264 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003265 y_modulo.remainder-1L;
3266 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003267 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003268 exception);
cristy4c08aed2011-07-01 19:47:50 +00003269 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003270 break;
3271 }
3272 case HorizontalTileEdgeVirtualPixelMethod:
3273 {
3274 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3275 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003276 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003277 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003278 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003279 break;
3280 }
3281 case VerticalTileEdgeVirtualPixelMethod:
3282 {
3283 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3284 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003285 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003286 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003287 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3288 break;
3289 }
3290 case BackgroundVirtualPixelMethod:
3291 case BlackVirtualPixelMethod:
3292 case GrayVirtualPixelMethod:
3293 case TransparentVirtualPixelMethod:
3294 case MaskVirtualPixelMethod:
3295 case WhiteVirtualPixelMethod:
3296 {
3297 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003298 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003299 break;
3300 }
3301 case EdgeVirtualPixelMethod:
3302 case CheckerTileVirtualPixelMethod:
3303 {
3304 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3305 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3306 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3307 {
3308 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003309 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003310 break;
3311 }
3312 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3313 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3314 exception);
3315 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3316 break;
3317 }
3318 case HorizontalTileVirtualPixelMethod:
3319 {
3320 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3321 {
3322 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003323 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003324 break;
3325 }
3326 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3327 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3328 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3329 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3330 exception);
3331 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3332 break;
3333 }
3334 case VerticalTileVirtualPixelMethod:
3335 {
3336 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3337 {
3338 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003339 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003340 break;
3341 }
3342 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3343 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3344 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3345 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3346 exception);
3347 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003348 break;
3349 }
3350 }
cristy4c08aed2011-07-01 19:47:50 +00003351 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003352 break;
cristyed231572011-07-14 02:18:59 +00003353 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003354 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003355 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003356 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003357 {
3358 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3359 s+=cache_info->metacontent_extent;
3360 }
cristy3ed852e2009-09-05 21:47:34 +00003361 continue;
3362 }
3363 /*
3364 Transfer a run of pixels.
3365 */
cristy4c08aed2011-07-01 19:47:50 +00003366 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3367 length,1UL,*virtual_nexus,exception);
3368 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003369 break;
cristy4c08aed2011-07-01 19:47:50 +00003370 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003371 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3372 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003373 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003374 {
cristy4c08aed2011-07-01 19:47:50 +00003375 (void) memcpy(s,r,(size_t) length);
3376 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003377 }
3378 }
3379 }
cristy4c08aed2011-07-01 19:47:50 +00003380 /*
3381 Free resources.
3382 */
cristy105ba3c2011-07-18 02:28:38 +00003383 if (virtual_metacontent != (void *) NULL)
3384 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003385 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3386 return(pixels);
3387}
3388
3389/*
3390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3391% %
3392% %
3393% %
3394+ G e t V i r t u a l P i x e l C a c h e %
3395% %
3396% %
3397% %
3398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3399%
3400% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3401% cache as defined by the geometry parameters. A pointer to the pixels
3402% is returned if the pixels are transferred, otherwise a NULL is returned.
3403%
3404% The format of the GetVirtualPixelCache() method is:
3405%
cristy4c08aed2011-07-01 19:47:50 +00003406% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003407% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3408% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003409% ExceptionInfo *exception)
3410%
3411% A description of each parameter follows:
3412%
3413% o image: the image.
3414%
3415% o virtual_pixel_method: the virtual pixel method.
3416%
3417% o x,y,columns,rows: These values define the perimeter of a region of
3418% pixels.
3419%
3420% o exception: return any errors or warnings in this structure.
3421%
3422*/
cristy4c08aed2011-07-01 19:47:50 +00003423static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003424 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3425 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003426{
3427 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003428 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003429
cristy5c9e6f22010-09-17 17:31:01 +00003430 const int
3431 id = GetOpenMPThreadId();
3432
cristy4c08aed2011-07-01 19:47:50 +00003433 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003434 *p;
cristy4c08aed2011-07-01 19:47:50 +00003435
cristye7cc7cf2010-09-21 13:26:47 +00003436 assert(image != (const Image *) NULL);
3437 assert(image->signature == MagickSignature);
3438 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003439 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003440 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003441 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003442 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003443 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003444 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003445}
3446
3447/*
3448%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3449% %
3450% %
3451% %
3452% G e t V i r t u a l P i x e l Q u e u e %
3453% %
3454% %
3455% %
3456%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3457%
cristy4c08aed2011-07-01 19:47:50 +00003458% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3459% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003460%
3461% The format of the GetVirtualPixelQueue() method is:
3462%
cristy4c08aed2011-07-01 19:47:50 +00003463% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003464%
3465% A description of each parameter follows:
3466%
3467% o image: the image.
3468%
3469*/
cristy4c08aed2011-07-01 19:47:50 +00003470MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003471{
3472 CacheInfo
3473 *cache_info;
3474
cristy2036f5c2010-09-19 21:18:17 +00003475 const int
3476 id = GetOpenMPThreadId();
3477
cristy3ed852e2009-09-05 21:47:34 +00003478 assert(image != (const Image *) NULL);
3479 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003480 assert(image->cache != (Cache) NULL);
3481 cache_info=(CacheInfo *) image->cache;
3482 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003483 if (cache_info->methods.get_virtual_pixels_handler !=
3484 (GetVirtualPixelsHandler) NULL)
3485 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003486 assert(id < (int) cache_info->number_threads);
3487 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003488}
3489
3490/*
3491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3492% %
3493% %
3494% %
3495% G e t V i r t u a l P i x e l s %
3496% %
3497% %
3498% %
3499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3500%
3501% GetVirtualPixels() returns an immutable pixel region. If the
3502% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003503% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003504% copy of the pixels or it may point to the original pixels in memory.
3505% Performance is maximized if the selected region is part of one row, or one
3506% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003507% (without a copy) if the image is in memory, or in a memory-mapped file. The
3508% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003509%
3510% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003511% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3512% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3513% access the meta-content (of type void) corresponding to the the
3514% region.
cristy3ed852e2009-09-05 21:47:34 +00003515%
3516% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3517%
3518% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3519% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3520% GetCacheViewAuthenticPixels() instead.
3521%
3522% The format of the GetVirtualPixels() method is:
3523%
cristy4c08aed2011-07-01 19:47:50 +00003524% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003525% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003526% ExceptionInfo *exception)
3527%
3528% A description of each parameter follows:
3529%
3530% o image: the image.
3531%
3532% o x,y,columns,rows: These values define the perimeter of a region of
3533% pixels.
3534%
3535% o exception: return any errors or warnings in this structure.
3536%
3537*/
cristy4c08aed2011-07-01 19:47:50 +00003538MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003539 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3540 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003541{
3542 CacheInfo
3543 *cache_info;
3544
cristy2036f5c2010-09-19 21:18:17 +00003545 const int
3546 id = GetOpenMPThreadId();
3547
cristy4c08aed2011-07-01 19:47:50 +00003548 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003549 *p;
cristy4c08aed2011-07-01 19:47:50 +00003550
cristy3ed852e2009-09-05 21:47:34 +00003551 assert(image != (const Image *) NULL);
3552 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003553 assert(image->cache != (Cache) NULL);
3554 cache_info=(CacheInfo *) image->cache;
3555 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003556 if (cache_info->methods.get_virtual_pixel_handler !=
3557 (GetVirtualPixelHandler) NULL)
3558 return(cache_info->methods.get_virtual_pixel_handler(image,
3559 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003560 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003561 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003562 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003563 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003564}
3565
3566/*
3567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3568% %
3569% %
3570% %
3571+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3572% %
3573% %
3574% %
3575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3576%
cristy4c08aed2011-07-01 19:47:50 +00003577% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3578% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003579%
3580% The format of the GetVirtualPixelsCache() method is:
3581%
cristy4c08aed2011-07-01 19:47:50 +00003582% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003583%
3584% A description of each parameter follows:
3585%
3586% o image: the image.
3587%
3588*/
cristy4c08aed2011-07-01 19:47:50 +00003589static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003590{
3591 CacheInfo
3592 *cache_info;
3593
cristy5c9e6f22010-09-17 17:31:01 +00003594 const int
3595 id = GetOpenMPThreadId();
3596
cristye7cc7cf2010-09-21 13:26:47 +00003597 assert(image != (const Image *) NULL);
3598 assert(image->signature == MagickSignature);
3599 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003600 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003601 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003602 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003603 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003604}
3605
3606/*
3607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3608% %
3609% %
3610% %
3611+ G e t V i r t u a l P i x e l s N e x u s %
3612% %
3613% %
3614% %
3615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3616%
3617% GetVirtualPixelsNexus() returns the pixels associated with the specified
3618% cache nexus.
3619%
3620% The format of the GetVirtualPixelsNexus() method is:
3621%
cristy4c08aed2011-07-01 19:47:50 +00003622% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003623% NexusInfo *nexus_info)
3624%
3625% A description of each parameter follows:
3626%
3627% o cache: the pixel cache.
3628%
3629% o nexus_info: the cache nexus to return the colormap pixels.
3630%
3631*/
cristya6577ff2011-09-02 19:54:26 +00003632MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003633 NexusInfo *nexus_info)
3634{
3635 CacheInfo
3636 *cache_info;
3637
cristye7cc7cf2010-09-21 13:26:47 +00003638 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003639 cache_info=(CacheInfo *) cache;
3640 assert(cache_info->signature == MagickSignature);
3641 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003642 return((Quantum *) NULL);
3643 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003644}
3645
3646/*
3647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3648% %
3649% %
3650% %
cristy3ed852e2009-09-05 21:47:34 +00003651+ O p e n P i x e l C a c h e %
3652% %
3653% %
3654% %
3655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3656%
3657% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3658% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003659% metacontent, and memory mapping the cache if it is disk based. The cache
3660% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003661%
3662% The format of the OpenPixelCache() method is:
3663%
3664% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3665% ExceptionInfo *exception)
3666%
3667% A description of each parameter follows:
3668%
3669% o image: the image.
3670%
3671% o mode: ReadMode, WriteMode, or IOMode.
3672%
3673% o exception: return any errors or warnings in this structure.
3674%
3675*/
3676
cristyd43a46b2010-01-21 02:13:41 +00003677static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003678{
3679 cache_info->mapped=MagickFalse;
cristye42639a2012-08-23 01:53:24 +00003680 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3681 (size_t) cache_info->length));
cristy4c08aed2011-07-01 19:47:50 +00003682 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003683 {
3684 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003685 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003686 cache_info->length);
3687 }
3688}
3689
3690static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3691{
3692 CacheInfo
3693 *cache_info;
3694
3695 MagickOffsetType
cristy3ed852e2009-09-05 21:47:34 +00003696 extent,
3697 offset;
3698
3699 cache_info=(CacheInfo *) image->cache;
3700 if (image->debug != MagickFalse)
3701 {
3702 char
3703 format[MaxTextExtent],
3704 message[MaxTextExtent];
3705
cristyb9080c92009-12-01 20:13:26 +00003706 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003707 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003708 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003709 cache_info->cache_filename,cache_info->file,format);
3710 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3711 }
3712 if (length != (MagickSizeType) ((MagickOffsetType) length))
3713 return(MagickFalse);
cristy911f2b12012-10-18 14:55:28 +00003714 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3715 if (offset < 0)
cristy3ed852e2009-09-05 21:47:34 +00003716 return(MagickFalse);
cristy911f2b12012-10-18 14:55:28 +00003717 if ((MagickSizeType) offset >= length)
cristy3ed852e2009-09-05 21:47:34 +00003718 return(MagickTrue);
cristy911f2b12012-10-18 14:55:28 +00003719 extent=(MagickOffsetType) length-1;
cristy3b5a2cf2012-10-18 14:50:08 +00003720#if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3721 {
3722 MagickOffsetType
3723 count;
3724
cristy911f2b12012-10-18 14:55:28 +00003725 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
cristy3b5a2cf2012-10-18 14:50:08 +00003726 if (count != (MagickOffsetType) 1)
3727 return(MagickFalse);
3728 }
3729#else
3730 {
3731 int
3732 status;
3733
cristy911f2b12012-10-18 14:55:28 +00003734 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
cristy3b5a2cf2012-10-18 14:50:08 +00003735 if (status != 0)
3736 return(MagickFalse);
3737 }
3738#endif
3739 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003740}
3741
3742static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3743 ExceptionInfo *exception)
3744{
cristy3ed852e2009-09-05 21:47:34 +00003745 CacheInfo
3746 *cache_info,
3747 source_info;
3748
cristyf3a6a9d2010-11-07 21:02:56 +00003749 char
3750 format[MaxTextExtent],
3751 message[MaxTextExtent];
3752
cristy4c08aed2011-07-01 19:47:50 +00003753 MagickBooleanType
3754 status;
3755
cristy3ed852e2009-09-05 21:47:34 +00003756 MagickSizeType
3757 length,
3758 number_pixels;
3759
cristy3ed852e2009-09-05 21:47:34 +00003760 size_t
cristye076a6e2010-08-15 19:59:43 +00003761 columns,
cristy3ed852e2009-09-05 21:47:34 +00003762 packet_size;
3763
cristye7cc7cf2010-09-21 13:26:47 +00003764 assert(image != (const Image *) NULL);
3765 assert(image->signature == MagickSignature);
3766 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003767 if (image->debug != MagickFalse)
3768 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3769 if ((image->columns == 0) || (image->rows == 0))
3770 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3771 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003772 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003773 source_info=(*cache_info);
3774 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003775 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003776 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003777 cache_info->storage_class=image->storage_class;
3778 cache_info->colorspace=image->colorspace;
cristy8a46d822012-08-28 23:32:39 +00003779 cache_info->alpha_trait=image->alpha_trait;
cristy183a5c72012-01-30 01:40:35 +00003780 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003781 cache_info->rows=image->rows;
3782 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003783 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003784 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003785 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3786 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003787 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003788 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003789 if (image->ping != MagickFalse)
3790 {
cristy73724512010-04-12 14:43:14 +00003791 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003792 cache_info->pixels=(Quantum *) NULL;
3793 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003794 cache_info->length=0;
3795 return(MagickTrue);
3796 }
cristy3ed852e2009-09-05 21:47:34 +00003797 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003798 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003799 if (image->metacontent_extent != 0)
3800 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003801 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003802 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003803 if (cache_info->columns != columns)
3804 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3805 image->filename);
3806 cache_info->length=length;
3807 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003808 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003809 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003810 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3811 {
3812 status=AcquireMagickResource(MemoryResource,cache_info->length);
3813 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3814 (cache_info->type == MemoryCache))
3815 {
cristyd43a46b2010-01-21 02:13:41 +00003816 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003817 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003818 cache_info->pixels=source_info.pixels;
3819 else
3820 {
3821 /*
3822 Create memory pixel cache.
3823 */
cristy4c08aed2011-07-01 19:47:50 +00003824 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003825 if (image->debug != MagickFalse)
3826 {
cristy32cacff2011-12-31 03:36:27 +00003827 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003828 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003829 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3830 cache_info->filename,cache_info->mapped != MagickFalse ?
3831 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003832 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003833 format);
cristy3ed852e2009-09-05 21:47:34 +00003834 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3835 message);
3836 }
cristy3ed852e2009-09-05 21:47:34 +00003837 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003838 cache_info->metacontent=(void *) NULL;
3839 if (cache_info->metacontent_extent != 0)
3840 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003841 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003842 if ((source_info.storage_class != UndefinedClass) &&
3843 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003844 {
cristy4c08aed2011-07-01 19:47:50 +00003845 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003846 exception);
3847 RelinquishPixelCachePixels(&source_info);
3848 }
cristy4c08aed2011-07-01 19:47:50 +00003849 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003850 }
3851 }
3852 RelinquishMagickResource(MemoryResource,cache_info->length);
3853 }
3854 /*
3855 Create pixel cache on disk.
3856 */
3857 status=AcquireMagickResource(DiskResource,cache_info->length);
3858 if (status == MagickFalse)
3859 {
3860 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003861 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003862 return(MagickFalse);
3863 }
cristy413f1302012-01-01 17:48:27 +00003864 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3865 {
3866 (void) ClosePixelCacheOnDisk(cache_info);
3867 *cache_info->cache_filename='\0';
3868 }
cristy3ed852e2009-09-05 21:47:34 +00003869 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3870 {
3871 RelinquishMagickResource(DiskResource,cache_info->length);
3872 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3873 image->filename);
3874 return(MagickFalse);
3875 }
3876 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3877 cache_info->length);
3878 if (status == MagickFalse)
3879 {
3880 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3881 image->filename);
3882 return(MagickFalse);
3883 }
cristyed231572011-07-14 02:18:59 +00003884 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003885 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003886 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003887 cache_info->type=DiskCache;
3888 else
3889 {
3890 status=AcquireMagickResource(MapResource,cache_info->length);
3891 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3892 (cache_info->type != MemoryCache))
3893 cache_info->type=DiskCache;
3894 else
3895 {
cristy4c08aed2011-07-01 19:47:50 +00003896 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003897 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003898 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003899 {
cristy3ed852e2009-09-05 21:47:34 +00003900 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003901 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003902 }
3903 else
3904 {
3905 /*
3906 Create file-backed memory-mapped pixel cache.
3907 */
cristy4c08aed2011-07-01 19:47:50 +00003908 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003909 (void) ClosePixelCacheOnDisk(cache_info);
3910 cache_info->type=MapCache;
3911 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003912 cache_info->metacontent=(void *) NULL;
3913 if (cache_info->metacontent_extent != 0)
3914 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003915 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003916 if ((source_info.storage_class != UndefinedClass) &&
3917 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003918 {
3919 status=ClonePixelCachePixels(cache_info,&source_info,
3920 exception);
3921 RelinquishPixelCachePixels(&source_info);
3922 }
3923 if (image->debug != MagickFalse)
3924 {
cristy413f1302012-01-01 17:48:27 +00003925 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003926 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003927 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003928 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003929 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003930 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003931 format);
cristy3ed852e2009-09-05 21:47:34 +00003932 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3933 message);
3934 }
cristy4c08aed2011-07-01 19:47:50 +00003935 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003936 }
3937 }
3938 RelinquishMagickResource(MapResource,cache_info->length);
3939 }
cristy4c08aed2011-07-01 19:47:50 +00003940 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003941 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003942 {
3943 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3944 RelinquishPixelCachePixels(&source_info);
3945 }
3946 if (image->debug != MagickFalse)
3947 {
cristyb9080c92009-12-01 20:13:26 +00003948 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003949 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003950 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003951 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003952 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003953 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003954 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3955 }
cristy4c08aed2011-07-01 19:47:50 +00003956 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003957}
3958
3959/*
3960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3961% %
3962% %
3963% %
3964+ P e r s i s t P i x e l C a c h e %
3965% %
3966% %
3967% %
3968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3969%
3970% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3971% persistent pixel cache is one that resides on disk and is not destroyed
3972% when the program exits.
3973%
3974% The format of the PersistPixelCache() method is:
3975%
3976% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3977% const MagickBooleanType attach,MagickOffsetType *offset,
3978% ExceptionInfo *exception)
3979%
3980% A description of each parameter follows:
3981%
3982% o image: the image.
3983%
3984% o filename: the persistent pixel cache filename.
3985%
cristyf3a6a9d2010-11-07 21:02:56 +00003986% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003987%
cristy3ed852e2009-09-05 21:47:34 +00003988% o initialize: A value other than zero initializes the persistent pixel
3989% cache.
3990%
3991% o offset: the offset in the persistent cache to store pixels.
3992%
3993% o exception: return any errors or warnings in this structure.
3994%
3995*/
3996MagickExport MagickBooleanType PersistPixelCache(Image *image,
3997 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3998 ExceptionInfo *exception)
3999{
4000 CacheInfo
4001 *cache_info,
4002 *clone_info;
4003
4004 Image
4005 clone_image;
4006
cristy3ed852e2009-09-05 21:47:34 +00004007 MagickBooleanType
4008 status;
4009
cristye076a6e2010-08-15 19:59:43 +00004010 ssize_t
4011 page_size;
4012
cristy3ed852e2009-09-05 21:47:34 +00004013 assert(image != (Image *) NULL);
4014 assert(image->signature == MagickSignature);
4015 if (image->debug != MagickFalse)
4016 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4017 assert(image->cache != (void *) NULL);
4018 assert(filename != (const char *) NULL);
4019 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004020 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004021 cache_info=(CacheInfo *) image->cache;
4022 assert(cache_info->signature == MagickSignature);
4023 if (attach != MagickFalse)
4024 {
4025 /*
cristy01b7eb02009-09-10 23:10:14 +00004026 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004027 */
4028 if (image->debug != MagickFalse)
4029 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004030 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004031 (void) CopyMagickString(cache_info->cache_filename,filename,
4032 MaxTextExtent);
4033 cache_info->type=DiskCache;
4034 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004035 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004036 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004037 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004038 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004039 }
cristy01b7eb02009-09-10 23:10:14 +00004040 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4041 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004042 {
cristyf84a1932010-01-03 18:00:18 +00004043 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004044 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004045 (cache_info->reference_count == 1))
4046 {
4047 int
4048 status;
4049
4050 /*
cristy01b7eb02009-09-10 23:10:14 +00004051 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004052 */
cristy320684d2011-09-23 14:55:47 +00004053 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004054 if (status == 0)
4055 {
4056 (void) CopyMagickString(cache_info->cache_filename,filename,
4057 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004058 *offset+=cache_info->length+page_size-(cache_info->length %
4059 page_size);
cristyf84a1932010-01-03 18:00:18 +00004060 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004061 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004062 if (image->debug != MagickFalse)
4063 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4064 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004065 return(MagickTrue);
4066 }
4067 }
cristyf84a1932010-01-03 18:00:18 +00004068 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004069 }
4070 /*
cristy01b7eb02009-09-10 23:10:14 +00004071 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004072 */
4073 clone_image=(*image);
4074 clone_info=(CacheInfo *) clone_image.cache;
4075 image->cache=ClonePixelCache(cache_info);
4076 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4077 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4078 cache_info->type=DiskCache;
4079 cache_info->offset=(*offset);
4080 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004081 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004082 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004083 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004084 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004085 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4086 return(status);
4087}
4088
4089/*
4090%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4091% %
4092% %
4093% %
cristyc11dace2012-01-24 16:39:46 +00004094+ 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 +00004095% %
4096% %
4097% %
4098%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4099%
cristyc11dace2012-01-24 16:39:46 +00004100% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4101% defined by the region rectangle and returns a pointer to the region. This
4102% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004103% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4104% pixels are transferred, otherwise a NULL is returned.
4105%
cristyc11dace2012-01-24 16:39:46 +00004106% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004107%
cristyc11dace2012-01-24 16:39:46 +00004108% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004109% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004110% const MagickBooleanType clone,NexusInfo *nexus_info,
4111% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004112%
4113% A description of each parameter follows:
4114%
4115% o image: the image.
4116%
4117% o x,y,columns,rows: These values define the perimeter of a region of
4118% pixels.
4119%
4120% o nexus_info: the cache nexus to set.
4121%
cristy65dbf172011-10-06 17:32:04 +00004122% o clone: clone the pixel cache.
4123%
cristy3ed852e2009-09-05 21:47:34 +00004124% o exception: return any errors or warnings in this structure.
4125%
4126*/
cristyc11dace2012-01-24 16:39:46 +00004127MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4128 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004129 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004130{
4131 CacheInfo
4132 *cache_info;
4133
4134 MagickOffsetType
4135 offset;
4136
4137 MagickSizeType
4138 number_pixels;
4139
4140 RectangleInfo
4141 region;
4142
4143 /*
4144 Validate pixel cache geometry.
4145 */
cristye7cc7cf2010-09-21 13:26:47 +00004146 assert(image != (const Image *) NULL);
4147 assert(image->signature == MagickSignature);
4148 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004149 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004150 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004151 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004152 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004153 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4154 {
4155 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004156 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004157 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004158 }
cristybb503372010-05-27 20:51:26 +00004159 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4160 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004161 {
4162 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004163 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004164 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004165 }
4166 offset=(MagickOffsetType) y*cache_info->columns+x;
4167 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004168 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004169 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4170 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4171 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004172 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004173 /*
4174 Return pixel cache.
4175 */
4176 region.x=x;
4177 region.y=y;
4178 region.width=columns;
4179 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004180 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004181}
4182
4183/*
4184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4185% %
4186% %
4187% %
4188+ 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 %
4189% %
4190% %
4191% %
4192%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4193%
4194% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4195% defined by the region rectangle and returns a pointer to the region. This
4196% region is subsequently transferred from the pixel cache with
4197% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4198% pixels are transferred, otherwise a NULL is returned.
4199%
4200% The format of the QueueAuthenticPixelsCache() method is:
4201%
cristy4c08aed2011-07-01 19:47:50 +00004202% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004203% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004204% ExceptionInfo *exception)
4205%
4206% A description of each parameter follows:
4207%
4208% o image: the image.
4209%
4210% o x,y,columns,rows: These values define the perimeter of a region of
4211% pixels.
4212%
4213% o exception: return any errors or warnings in this structure.
4214%
4215*/
cristy4c08aed2011-07-01 19:47:50 +00004216static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004217 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004218 ExceptionInfo *exception)
4219{
4220 CacheInfo
4221 *cache_info;
4222
cristy5c9e6f22010-09-17 17:31:01 +00004223 const int
4224 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004225
cristy4c08aed2011-07-01 19:47:50 +00004226 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004227 *q;
cristy4c08aed2011-07-01 19:47:50 +00004228
cristye7cc7cf2010-09-21 13:26:47 +00004229 assert(image != (const Image *) NULL);
4230 assert(image->signature == MagickSignature);
4231 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004232 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004233 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004234 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004235 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004236 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004237 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004238}
4239
4240/*
4241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4242% %
4243% %
4244% %
4245% Q u e u e A u t h e n t i c P i x e l s %
4246% %
4247% %
4248% %
4249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4250%
4251% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004252% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004253% region is returned, otherwise NULL is returned. The returned pointer may
4254% point to a temporary working buffer for the pixels or it may point to the
4255% final location of the pixels in memory.
4256%
4257% Write-only access means that any existing pixel values corresponding to
4258% the region are ignored. This is useful if the initial image is being
4259% created from scratch, or if the existing pixel values are to be
4260% completely replaced without need to refer to their pre-existing values.
4261% The application is free to read and write the pixel buffer returned by
4262% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4263% initialize the pixel array values. Initializing pixel array values is the
4264% application's responsibility.
4265%
4266% Performance is maximized if the selected region is part of one row, or
4267% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004268% pixels in-place (without a copy) if the image is in memory, or in a
4269% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004270% by the user.
4271%
4272% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004273% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4274% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4275% obtain the meta-content (of type void) corresponding to the region.
4276% Once the Quantum (and/or Quantum) array has been updated, the
4277% changes must be saved back to the underlying image using
4278% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004279%
4280% The format of the QueueAuthenticPixels() method is:
4281%
cristy4c08aed2011-07-01 19:47:50 +00004282% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004283% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004284% ExceptionInfo *exception)
4285%
4286% A description of each parameter follows:
4287%
4288% o image: the image.
4289%
4290% o x,y,columns,rows: These values define the perimeter of a region of
4291% pixels.
4292%
4293% o exception: return any errors or warnings in this structure.
4294%
4295*/
cristy4c08aed2011-07-01 19:47:50 +00004296MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004297 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004298 ExceptionInfo *exception)
4299{
4300 CacheInfo
4301 *cache_info;
4302
cristy2036f5c2010-09-19 21:18:17 +00004303 const int
4304 id = GetOpenMPThreadId();
4305
cristy4c08aed2011-07-01 19:47:50 +00004306 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004307 *q;
cristy4c08aed2011-07-01 19:47:50 +00004308
cristy3ed852e2009-09-05 21:47:34 +00004309 assert(image != (Image *) NULL);
4310 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004311 assert(image->cache != (Cache) NULL);
4312 cache_info=(CacheInfo *) image->cache;
4313 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004314 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004315 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004316 {
cristyc36c8822012-02-14 14:02:36 +00004317 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4318 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004319 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004320 }
cristy2036f5c2010-09-19 21:18:17 +00004321 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004322 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004323 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004324 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004325}
4326
4327/*
4328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4329% %
4330% %
4331% %
cristy4c08aed2011-07-01 19:47:50 +00004332+ 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 +00004333% %
4334% %
4335% %
4336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4337%
cristy4c08aed2011-07-01 19:47:50 +00004338% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004339% the pixel cache.
4340%
cristy4c08aed2011-07-01 19:47:50 +00004341% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004342%
cristy4c08aed2011-07-01 19:47:50 +00004343% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004344% NexusInfo *nexus_info,ExceptionInfo *exception)
4345%
4346% A description of each parameter follows:
4347%
4348% o cache_info: the pixel cache.
4349%
cristy4c08aed2011-07-01 19:47:50 +00004350% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004351%
4352% o exception: return any errors or warnings in this structure.
4353%
4354*/
cristy4c08aed2011-07-01 19:47:50 +00004355static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004356 NexusInfo *nexus_info,ExceptionInfo *exception)
4357{
4358 MagickOffsetType
4359 count,
4360 offset;
4361
4362 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004363 extent,
4364 length;
cristy3ed852e2009-09-05 21:47:34 +00004365
cristybb503372010-05-27 20:51:26 +00004366 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004367 y;
4368
cristy4c08aed2011-07-01 19:47:50 +00004369 register unsigned char
4370 *restrict q;
4371
cristybb503372010-05-27 20:51:26 +00004372 size_t
cristy3ed852e2009-09-05 21:47:34 +00004373 rows;
4374
cristy4c08aed2011-07-01 19:47:50 +00004375 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004376 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004377 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004378 return(MagickTrue);
4379 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4380 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004381 length=(MagickSizeType) nexus_info->region.width*
4382 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004383 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004384 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004385 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004386 switch (cache_info->type)
4387 {
4388 case MemoryCache:
4389 case MapCache:
4390 {
cristy4c08aed2011-07-01 19:47:50 +00004391 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004392 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004393
4394 /*
cristy4c08aed2011-07-01 19:47:50 +00004395 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004396 */
cristydd341db2010-03-04 19:06:38 +00004397 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004398 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004399 {
cristy48078b12010-09-23 17:11:01 +00004400 length=extent;
cristydd341db2010-03-04 19:06:38 +00004401 rows=1UL;
4402 }
cristy4c08aed2011-07-01 19:47:50 +00004403 p=(unsigned char *) cache_info->metacontent+offset*
4404 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004405 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004406 {
cristy8f036fe2010-09-18 02:02:00 +00004407 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004408 p+=cache_info->metacontent_extent*cache_info->columns;
4409 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004410 }
4411 break;
4412 }
4413 case DiskCache:
4414 {
4415 /*
cristy4c08aed2011-07-01 19:47:50 +00004416 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004417 */
4418 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4419 {
4420 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4421 cache_info->cache_filename);
4422 return(MagickFalse);
4423 }
cristydd341db2010-03-04 19:06:38 +00004424 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004425 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004426 {
cristy48078b12010-09-23 17:11:01 +00004427 length=extent;
cristydd341db2010-03-04 19:06:38 +00004428 rows=1UL;
4429 }
cristy48078b12010-09-23 17:11:01 +00004430 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004431 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004432 {
cristy48078b12010-09-23 17:11:01 +00004433 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004434 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004435 cache_info->metacontent_extent,length,(unsigned char *) q);
4436 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004437 break;
4438 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004439 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004440 }
cristyc11dace2012-01-24 16:39:46 +00004441 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4442 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004443 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004444 {
4445 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4446 cache_info->cache_filename);
4447 return(MagickFalse);
4448 }
4449 break;
4450 }
4451 default:
4452 break;
4453 }
4454 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004455 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004456 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004457 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004458 nexus_info->region.width,(double) nexus_info->region.height,(double)
4459 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004460 return(MagickTrue);
4461}
4462
4463/*
4464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4465% %
4466% %
4467% %
4468+ R e a d P i x e l C a c h e P i x e l s %
4469% %
4470% %
4471% %
4472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4473%
4474% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4475% cache.
4476%
4477% The format of the ReadPixelCachePixels() method is:
4478%
4479% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4480% NexusInfo *nexus_info,ExceptionInfo *exception)
4481%
4482% A description of each parameter follows:
4483%
4484% o cache_info: the pixel cache.
4485%
4486% o nexus_info: the cache nexus to read the pixels.
4487%
4488% o exception: return any errors or warnings in this structure.
4489%
4490*/
4491static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4492 NexusInfo *nexus_info,ExceptionInfo *exception)
4493{
4494 MagickOffsetType
4495 count,
4496 offset;
4497
4498 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004499 extent,
4500 length;
cristy3ed852e2009-09-05 21:47:34 +00004501
cristy4c08aed2011-07-01 19:47:50 +00004502 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004503 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004504
cristye076a6e2010-08-15 19:59:43 +00004505 register ssize_t
4506 y;
4507
cristybb503372010-05-27 20:51:26 +00004508 size_t
cristy3ed852e2009-09-05 21:47:34 +00004509 rows;
4510
cristy4c08aed2011-07-01 19:47:50 +00004511 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004512 return(MagickTrue);
4513 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4514 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004515 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004516 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004517 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004518 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004519 q=nexus_info->pixels;
4520 switch (cache_info->type)
4521 {
4522 case MemoryCache:
4523 case MapCache:
4524 {
cristy4c08aed2011-07-01 19:47:50 +00004525 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004526 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004527
4528 /*
4529 Read pixels from memory.
4530 */
cristydd341db2010-03-04 19:06:38 +00004531 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004532 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004533 {
cristy48078b12010-09-23 17:11:01 +00004534 length=extent;
cristydd341db2010-03-04 19:06:38 +00004535 rows=1UL;
4536 }
cristyed231572011-07-14 02:18:59 +00004537 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004538 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004539 {
cristy8f036fe2010-09-18 02:02:00 +00004540 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004541 p+=cache_info->number_channels*cache_info->columns;
4542 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004543 }
4544 break;
4545 }
4546 case DiskCache:
4547 {
4548 /*
4549 Read pixels from disk.
4550 */
4551 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4552 {
4553 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4554 cache_info->cache_filename);
4555 return(MagickFalse);
4556 }
cristydd341db2010-03-04 19:06:38 +00004557 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004558 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004559 {
cristy48078b12010-09-23 17:11:01 +00004560 length=extent;
cristydd341db2010-03-04 19:06:38 +00004561 rows=1UL;
4562 }
cristybb503372010-05-27 20:51:26 +00004563 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004564 {
4565 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004566 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004567 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004568 break;
4569 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004570 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004571 }
cristyc11dace2012-01-24 16:39:46 +00004572 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4573 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004574 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004575 {
4576 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4577 cache_info->cache_filename);
4578 return(MagickFalse);
4579 }
4580 break;
4581 }
4582 default:
4583 break;
4584 }
4585 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004586 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004587 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004588 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004589 nexus_info->region.width,(double) nexus_info->region.height,(double)
4590 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004591 return(MagickTrue);
4592}
4593
4594/*
4595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4596% %
4597% %
4598% %
4599+ R e f e r e n c e P i x e l C a c h e %
4600% %
4601% %
4602% %
4603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4604%
4605% ReferencePixelCache() increments the reference count associated with the
4606% pixel cache returning a pointer to the cache.
4607%
4608% The format of the ReferencePixelCache method is:
4609%
4610% Cache ReferencePixelCache(Cache cache_info)
4611%
4612% A description of each parameter follows:
4613%
4614% o cache_info: the pixel cache.
4615%
4616*/
cristya6577ff2011-09-02 19:54:26 +00004617MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004618{
4619 CacheInfo
4620 *cache_info;
4621
4622 assert(cache != (Cache *) NULL);
4623 cache_info=(CacheInfo *) cache;
4624 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004625 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004626 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004627 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004628 return(cache_info);
4629}
4630
4631/*
4632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4633% %
4634% %
4635% %
4636+ S e t P i x e l C a c h e M e t h o d s %
4637% %
4638% %
4639% %
4640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4641%
4642% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4643%
4644% The format of the SetPixelCacheMethods() method is:
4645%
4646% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4647%
4648% A description of each parameter follows:
4649%
4650% o cache: the pixel cache.
4651%
4652% o cache_methods: Specifies a pointer to a CacheMethods structure.
4653%
4654*/
cristya6577ff2011-09-02 19:54:26 +00004655MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004656{
4657 CacheInfo
4658 *cache_info;
4659
4660 GetOneAuthenticPixelFromHandler
4661 get_one_authentic_pixel_from_handler;
4662
4663 GetOneVirtualPixelFromHandler
4664 get_one_virtual_pixel_from_handler;
4665
4666 /*
4667 Set cache pixel methods.
4668 */
4669 assert(cache != (Cache) NULL);
4670 assert(cache_methods != (CacheMethods *) NULL);
4671 cache_info=(CacheInfo *) cache;
4672 assert(cache_info->signature == MagickSignature);
4673 if (cache_info->debug != MagickFalse)
4674 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4675 cache_info->filename);
4676 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4677 cache_info->methods.get_virtual_pixel_handler=
4678 cache_methods->get_virtual_pixel_handler;
4679 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4680 cache_info->methods.destroy_pixel_handler=
4681 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004682 if (cache_methods->get_virtual_metacontent_from_handler !=
4683 (GetVirtualMetacontentFromHandler) NULL)
4684 cache_info->methods.get_virtual_metacontent_from_handler=
4685 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004686 if (cache_methods->get_authentic_pixels_handler !=
4687 (GetAuthenticPixelsHandler) NULL)
4688 cache_info->methods.get_authentic_pixels_handler=
4689 cache_methods->get_authentic_pixels_handler;
4690 if (cache_methods->queue_authentic_pixels_handler !=
4691 (QueueAuthenticPixelsHandler) NULL)
4692 cache_info->methods.queue_authentic_pixels_handler=
4693 cache_methods->queue_authentic_pixels_handler;
4694 if (cache_methods->sync_authentic_pixels_handler !=
4695 (SyncAuthenticPixelsHandler) NULL)
4696 cache_info->methods.sync_authentic_pixels_handler=
4697 cache_methods->sync_authentic_pixels_handler;
4698 if (cache_methods->get_authentic_pixels_from_handler !=
4699 (GetAuthenticPixelsFromHandler) NULL)
4700 cache_info->methods.get_authentic_pixels_from_handler=
4701 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004702 if (cache_methods->get_authentic_metacontent_from_handler !=
4703 (GetAuthenticMetacontentFromHandler) NULL)
4704 cache_info->methods.get_authentic_metacontent_from_handler=
4705 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004706 get_one_virtual_pixel_from_handler=
4707 cache_info->methods.get_one_virtual_pixel_from_handler;
4708 if (get_one_virtual_pixel_from_handler !=
4709 (GetOneVirtualPixelFromHandler) NULL)
4710 cache_info->methods.get_one_virtual_pixel_from_handler=
4711 cache_methods->get_one_virtual_pixel_from_handler;
4712 get_one_authentic_pixel_from_handler=
4713 cache_methods->get_one_authentic_pixel_from_handler;
4714 if (get_one_authentic_pixel_from_handler !=
4715 (GetOneAuthenticPixelFromHandler) NULL)
4716 cache_info->methods.get_one_authentic_pixel_from_handler=
4717 cache_methods->get_one_authentic_pixel_from_handler;
4718}
4719
4720/*
4721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4722% %
4723% %
4724% %
4725+ S e t P i x e l C a c h e N e x u s P i x e l s %
4726% %
4727% %
4728% %
4729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4730%
4731% SetPixelCacheNexusPixels() defines the region of the cache for the
4732% specified cache nexus.
4733%
4734% The format of the SetPixelCacheNexusPixels() method is:
4735%
cristy265a2b22012-05-11 12:48:50 +00004736% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004737% const RectangleInfo *region,NexusInfo *nexus_info,
4738% ExceptionInfo *exception)
4739%
4740% A description of each parameter follows:
4741%
4742% o image: the image.
4743%
cristy265a2b22012-05-11 12:48:50 +00004744% o mode: ReadMode, WriteMode, or IOMode.
4745%
cristy3ed852e2009-09-05 21:47:34 +00004746% o region: A pointer to the RectangleInfo structure that defines the
4747% region of this particular cache nexus.
4748%
4749% o nexus_info: the cache nexus to set.
4750%
4751% o exception: return any errors or warnings in this structure.
4752%
4753*/
cristyabd6e372010-09-15 19:11:26 +00004754
cristyf1832792012-05-08 18:38:18 +00004755static inline MagickBooleanType AcquireCacheNexusPixels(
4756 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4757 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004758{
4759 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4760 return(MagickFalse);
4761 nexus_info->mapped=MagickFalse;
cristye42639a2012-08-23 01:53:24 +00004762 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4763 (size_t) nexus_info->length));
cristy4c08aed2011-07-01 19:47:50 +00004764 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004765 {
4766 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004767 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004768 nexus_info->length);
4769 }
cristy4c08aed2011-07-01 19:47:50 +00004770 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004771 {
4772 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004773 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004774 cache_info->filename);
4775 return(MagickFalse);
4776 }
4777 return(MagickTrue);
4778}
4779
cristyadf82722012-05-11 17:34:16 +00004780static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4781 const MapMode mode)
4782{
cristyfc5845e2012-05-11 18:18:13 +00004783 if (mode == ReadMode)
4784 {
4785 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4786 return;
4787 }
4788 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004789}
4790
cristy265a2b22012-05-11 12:48:50 +00004791static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004792 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4793{
4794 CacheInfo
4795 *cache_info;
4796
4797 MagickBooleanType
4798 status;
4799
cristy3ed852e2009-09-05 21:47:34 +00004800 MagickSizeType
4801 length,
4802 number_pixels;
4803
cristy3ed852e2009-09-05 21:47:34 +00004804 cache_info=(CacheInfo *) image->cache;
4805 assert(cache_info->signature == MagickSignature);
4806 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004807 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004808 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004809 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004810 {
cristybb503372010-05-27 20:51:26 +00004811 ssize_t
cristybad067a2010-02-15 17:20:55 +00004812 x,
4813 y;
cristy3ed852e2009-09-05 21:47:34 +00004814
cristyeaedf062010-05-29 22:36:02 +00004815 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4816 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004817 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4818 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004819 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004820 ((nexus_info->region.width == cache_info->columns) ||
4821 ((nexus_info->region.width % cache_info->columns) == 0)))))
4822 {
4823 MagickOffsetType
4824 offset;
4825
4826 /*
4827 Pixels are accessed directly from memory.
4828 */
4829 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4830 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004831 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004832 offset;
4833 nexus_info->metacontent=(void *) NULL;
4834 if (cache_info->metacontent_extent != 0)
4835 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4836 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004837 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004838 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004839 }
4840 }
4841 /*
4842 Pixels are stored in a cache region until they are synced to the cache.
4843 */
4844 number_pixels=(MagickSizeType) nexus_info->region.width*
4845 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004846 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004847 if (cache_info->metacontent_extent != 0)
4848 length+=number_pixels*cache_info->metacontent_extent;
4849 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004850 {
4851 nexus_info->length=length;
4852 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4853 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004854 {
4855 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004856 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004857 }
cristy3ed852e2009-09-05 21:47:34 +00004858 }
4859 else
4860 if (nexus_info->length != length)
4861 {
4862 RelinquishCacheNexusPixels(nexus_info);
4863 nexus_info->length=length;
4864 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4865 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004866 {
4867 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004868 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004869 }
cristy3ed852e2009-09-05 21:47:34 +00004870 }
4871 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004872 nexus_info->metacontent=(void *) NULL;
4873 if (cache_info->metacontent_extent != 0)
4874 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004875 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004876 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004877 return(nexus_info->pixels);
4878}
4879
4880/*
4881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4882% %
4883% %
4884% %
4885% 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 %
4886% %
4887% %
4888% %
4889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4890%
4891% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4892% pixel cache and returns the previous setting. A virtual pixel is any pixel
4893% access that is outside the boundaries of the image cache.
4894%
4895% The format of the SetPixelCacheVirtualMethod() method is:
4896%
cristy387430f2012-02-07 13:09:46 +00004897% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4898% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004899%
4900% A description of each parameter follows:
4901%
4902% o image: the image.
4903%
4904% o virtual_pixel_method: choose the type of virtual pixel.
4905%
cristy387430f2012-02-07 13:09:46 +00004906% o exception: return any errors or warnings in this structure.
4907%
cristy3ed852e2009-09-05 21:47:34 +00004908*/
cristy3d4cb882012-02-07 19:11:26 +00004909
4910static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4911 ExceptionInfo *exception)
4912{
4913 CacheInfo
4914 *cache_info;
4915
cristyf2719112012-05-06 18:38:46 +00004916 CacheView
4917 *image_view;
4918
cristy3d4cb882012-02-07 19:11:26 +00004919 MagickBooleanType
4920 status;
4921
4922 ssize_t
4923 y;
4924
4925 assert(image != (Image *) NULL);
4926 assert(image->signature == MagickSignature);
4927 if (image->debug != MagickFalse)
4928 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4929 assert(image->cache != (Cache) NULL);
4930 cache_info=(CacheInfo *) image->cache;
4931 assert(cache_info->signature == MagickSignature);
cristy8a46d822012-08-28 23:32:39 +00004932 image->alpha_trait=BlendPixelTrait;
cristy3d4cb882012-02-07 19:11:26 +00004933 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004934 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004935#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +00004936 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00004937 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004938#endif
4939 for (y=0; y < (ssize_t) image->rows; y++)
4940 {
cristy3d4cb882012-02-07 19:11:26 +00004941 register Quantum
4942 *restrict q;
4943
4944 register ssize_t
4945 x;
4946
4947 if (status == MagickFalse)
4948 continue;
cristy23d198a2012-03-13 13:48:08 +00004949 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004950 if (q == (Quantum *) NULL)
4951 {
4952 status=MagickFalse;
4953 continue;
4954 }
4955 for (x=0; x < (ssize_t) image->columns; x++)
4956 {
4957 SetPixelAlpha(image,alpha,q);
4958 q+=GetPixelChannels(image);
4959 }
cristy23d198a2012-03-13 13:48:08 +00004960 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004961 }
cristy23d198a2012-03-13 13:48:08 +00004962 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004963 return(status);
4964}
4965
cristy387430f2012-02-07 13:09:46 +00004966MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4967 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004968{
4969 CacheInfo
4970 *cache_info;
4971
4972 VirtualPixelMethod
4973 method;
4974
4975 assert(image != (Image *) NULL);
4976 assert(image->signature == MagickSignature);
4977 if (image->debug != MagickFalse)
4978 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4979 assert(image->cache != (Cache) NULL);
4980 cache_info=(CacheInfo *) image->cache;
4981 assert(cache_info->signature == MagickSignature);
4982 method=cache_info->virtual_pixel_method;
4983 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy13c10082012-05-29 11:22:12 +00004984 if ((image->columns != 0) && (image->rows != 0))
4985 switch (virtual_pixel_method)
cristy387430f2012-02-07 13:09:46 +00004986 {
cristy13c10082012-05-29 11:22:12 +00004987 case BackgroundVirtualPixelMethod:
4988 {
cristy8a46d822012-08-28 23:32:39 +00004989 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4990 (image->alpha_trait != BlendPixelTrait))
cristy13c10082012-05-29 11:22:12 +00004991 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy6386b792012-06-23 17:44:57 +00004992 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4993 (IsGrayColorspace(image->colorspace) != MagickFalse))
cristyb09db112012-07-11 12:04:31 +00004994 (void) TransformImageColorspace(image,RGBColorspace,exception);
cristy13c10082012-05-29 11:22:12 +00004995 break;
4996 }
4997 case TransparentVirtualPixelMethod:
4998 {
cristy8a46d822012-08-28 23:32:39 +00004999 if (image->alpha_trait != BlendPixelTrait)
cristy13c10082012-05-29 11:22:12 +00005000 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5001 break;
5002 }
5003 default:
5004 break;
cristy387430f2012-02-07 13:09:46 +00005005 }
cristy3ed852e2009-09-05 21:47:34 +00005006 return(method);
5007}
5008
5009/*
5010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5011% %
5012% %
5013% %
5014+ 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 %
5015% %
5016% %
5017% %
5018%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5019%
5020% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5021% in-memory or disk cache. The method returns MagickTrue if the pixel region
5022% is synced, otherwise MagickFalse.
5023%
5024% The format of the SyncAuthenticPixelCacheNexus() method is:
5025%
5026% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5027% NexusInfo *nexus_info,ExceptionInfo *exception)
5028%
5029% A description of each parameter follows:
5030%
5031% o image: the image.
5032%
5033% o nexus_info: the cache nexus to sync.
5034%
5035% o exception: return any errors or warnings in this structure.
5036%
5037*/
cristya6577ff2011-09-02 19:54:26 +00005038MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005039 NexusInfo *nexus_info,ExceptionInfo *exception)
5040{
5041 CacheInfo
5042 *cache_info;
5043
5044 MagickBooleanType
5045 status;
5046
5047 /*
5048 Transfer pixels to the cache.
5049 */
5050 assert(image != (Image *) NULL);
5051 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005052 if (image->cache == (Cache) NULL)
5053 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5054 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005055 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005056 if (cache_info->type == UndefinedCache)
5057 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005058 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005059 return(MagickTrue);
5060 assert(cache_info->signature == MagickSignature);
5061 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005062 if ((cache_info->metacontent_extent != 0) &&
5063 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005064 return(MagickFalse);
5065 return(status);
5066}
5067
5068/*
5069%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5070% %
5071% %
5072% %
5073+ S y n c A u t h e n t i c P i x e l C a c h e %
5074% %
5075% %
5076% %
5077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5078%
5079% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5080% or disk cache. The method returns MagickTrue if the pixel region is synced,
5081% otherwise MagickFalse.
5082%
5083% The format of the SyncAuthenticPixelsCache() method is:
5084%
5085% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5086% ExceptionInfo *exception)
5087%
5088% A description of each parameter follows:
5089%
5090% o image: the image.
5091%
5092% o exception: return any errors or warnings in this structure.
5093%
5094*/
5095static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5096 ExceptionInfo *exception)
5097{
5098 CacheInfo
5099 *cache_info;
5100
cristy5c9e6f22010-09-17 17:31:01 +00005101 const int
5102 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005103
cristy4c08aed2011-07-01 19:47:50 +00005104 MagickBooleanType
5105 status;
5106
cristye7cc7cf2010-09-21 13:26:47 +00005107 assert(image != (Image *) NULL);
5108 assert(image->signature == MagickSignature);
5109 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005110 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005111 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005112 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005113 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5114 exception);
5115 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005116}
5117
5118/*
5119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5120% %
5121% %
5122% %
5123% S y n c A u t h e n t i c P i x e l s %
5124% %
5125% %
5126% %
5127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5128%
5129% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5130% The method returns MagickTrue if the pixel region is flushed, otherwise
5131% MagickFalse.
5132%
5133% The format of the SyncAuthenticPixels() method is:
5134%
5135% MagickBooleanType SyncAuthenticPixels(Image *image,
5136% ExceptionInfo *exception)
5137%
5138% A description of each parameter follows:
5139%
5140% o image: the image.
5141%
5142% o exception: return any errors or warnings in this structure.
5143%
5144*/
5145MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5146 ExceptionInfo *exception)
5147{
5148 CacheInfo
5149 *cache_info;
5150
cristy2036f5c2010-09-19 21:18:17 +00005151 const int
5152 id = GetOpenMPThreadId();
5153
cristy4c08aed2011-07-01 19:47:50 +00005154 MagickBooleanType
5155 status;
5156
cristy3ed852e2009-09-05 21:47:34 +00005157 assert(image != (Image *) NULL);
5158 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005159 assert(image->cache != (Cache) NULL);
5160 cache_info=(CacheInfo *) image->cache;
5161 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005162 if (cache_info->methods.sync_authentic_pixels_handler !=
5163 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005164 {
5165 status=cache_info->methods.sync_authentic_pixels_handler(image,
5166 exception);
5167 return(status);
5168 }
cristy2036f5c2010-09-19 21:18:17 +00005169 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005170 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5171 exception);
5172 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005173}
5174
5175/*
5176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5177% %
5178% %
5179% %
cristyd1dd6e42011-09-04 01:46:08 +00005180+ 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 +00005181% %
5182% %
5183% %
5184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5185%
5186% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5187% The method returns MagickTrue if the pixel region is flushed, otherwise
5188% MagickFalse.
5189%
5190% The format of the SyncImagePixelCache() method is:
5191%
5192% MagickBooleanType SyncImagePixelCache(Image *image,
5193% ExceptionInfo *exception)
5194%
5195% A description of each parameter follows:
5196%
5197% o image: the image.
5198%
5199% o exception: return any errors or warnings in this structure.
5200%
5201*/
cristyd1dd6e42011-09-04 01:46:08 +00005202MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005203 ExceptionInfo *exception)
5204{
5205 CacheInfo
5206 *cache_info;
5207
5208 assert(image != (Image *) NULL);
5209 assert(exception != (ExceptionInfo *) NULL);
5210 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5211 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5212}
5213
5214/*
5215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5216% %
5217% %
5218% %
cristy4c08aed2011-07-01 19:47:50 +00005219+ 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 +00005220% %
5221% %
5222% %
5223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5224%
cristy4c08aed2011-07-01 19:47:50 +00005225% WritePixelCacheMetacontent() writes the meta-content to the specified region
5226% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005227%
cristy4c08aed2011-07-01 19:47:50 +00005228% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005229%
cristy4c08aed2011-07-01 19:47:50 +00005230% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005231% NexusInfo *nexus_info,ExceptionInfo *exception)
5232%
5233% A description of each parameter follows:
5234%
5235% o cache_info: the pixel cache.
5236%
cristy4c08aed2011-07-01 19:47:50 +00005237% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005238%
5239% o exception: return any errors or warnings in this structure.
5240%
5241*/
cristy4c08aed2011-07-01 19:47:50 +00005242static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005243 NexusInfo *nexus_info,ExceptionInfo *exception)
5244{
5245 MagickOffsetType
5246 count,
5247 offset;
5248
5249 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005250 extent,
5251 length;
cristy3ed852e2009-09-05 21:47:34 +00005252
cristy4c08aed2011-07-01 19:47:50 +00005253 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005254 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005255
cristybb503372010-05-27 20:51:26 +00005256 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005257 y;
5258
cristybb503372010-05-27 20:51:26 +00005259 size_t
cristy3ed852e2009-09-05 21:47:34 +00005260 rows;
5261
cristy4c08aed2011-07-01 19:47:50 +00005262 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005263 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005264 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005265 return(MagickTrue);
5266 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5267 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005268 length=(MagickSizeType) nexus_info->region.width*
5269 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005270 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005271 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005272 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005273 switch (cache_info->type)
5274 {
5275 case MemoryCache:
5276 case MapCache:
5277 {
cristy4c08aed2011-07-01 19:47:50 +00005278 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005279 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005280
5281 /*
cristy4c08aed2011-07-01 19:47:50 +00005282 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005283 */
cristydd341db2010-03-04 19:06:38 +00005284 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005285 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005286 {
cristy48078b12010-09-23 17:11:01 +00005287 length=extent;
cristydd341db2010-03-04 19:06:38 +00005288 rows=1UL;
5289 }
cristy4c08aed2011-07-01 19:47:50 +00005290 q=(unsigned char *) cache_info->metacontent+offset*
5291 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005292 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005293 {
cristy8f036fe2010-09-18 02:02:00 +00005294 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005295 p+=nexus_info->region.width*cache_info->metacontent_extent;
5296 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005297 }
5298 break;
5299 }
5300 case DiskCache:
5301 {
5302 /*
cristy4c08aed2011-07-01 19:47:50 +00005303 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005304 */
5305 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5306 {
5307 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5308 cache_info->cache_filename);
5309 return(MagickFalse);
5310 }
cristydd341db2010-03-04 19:06:38 +00005311 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005312 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005313 {
cristy48078b12010-09-23 17:11:01 +00005314 length=extent;
cristydd341db2010-03-04 19:06:38 +00005315 rows=1UL;
5316 }
cristy48078b12010-09-23 17:11:01 +00005317 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005318 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005319 {
cristy48078b12010-09-23 17:11:01 +00005320 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005321 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005322 cache_info->metacontent_extent,length,(const unsigned char *) p);
5323 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005324 break;
cristy4c08aed2011-07-01 19:47:50 +00005325 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005326 offset+=cache_info->columns;
5327 }
cristyc11dace2012-01-24 16:39:46 +00005328 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5329 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005330 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005331 {
5332 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5333 cache_info->cache_filename);
5334 return(MagickFalse);
5335 }
5336 break;
5337 }
5338 default:
5339 break;
5340 }
5341 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005342 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005343 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005344 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005345 nexus_info->region.width,(double) nexus_info->region.height,(double)
5346 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005347 return(MagickTrue);
5348}
5349
5350/*
5351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5352% %
5353% %
5354% %
5355+ W r i t e C a c h e P i x e l s %
5356% %
5357% %
5358% %
5359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5360%
5361% WritePixelCachePixels() writes image pixels to the specified region of the
5362% pixel cache.
5363%
5364% The format of the WritePixelCachePixels() method is:
5365%
5366% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5367% NexusInfo *nexus_info,ExceptionInfo *exception)
5368%
5369% A description of each parameter follows:
5370%
5371% o cache_info: the pixel cache.
5372%
5373% o nexus_info: the cache nexus to write the pixels.
5374%
5375% o exception: return any errors or warnings in this structure.
5376%
5377*/
5378static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5379 NexusInfo *nexus_info,ExceptionInfo *exception)
5380{
5381 MagickOffsetType
5382 count,
5383 offset;
5384
5385 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005386 extent,
5387 length;
cristy3ed852e2009-09-05 21:47:34 +00005388
cristy4c08aed2011-07-01 19:47:50 +00005389 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005390 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005391
cristybb503372010-05-27 20:51:26 +00005392 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005393 y;
5394
cristybb503372010-05-27 20:51:26 +00005395 size_t
cristy3ed852e2009-09-05 21:47:34 +00005396 rows;
5397
cristy4c08aed2011-07-01 19:47:50 +00005398 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005399 return(MagickTrue);
5400 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5401 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005402 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005403 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005404 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005405 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005406 p=nexus_info->pixels;
5407 switch (cache_info->type)
5408 {
5409 case MemoryCache:
5410 case MapCache:
5411 {
cristy4c08aed2011-07-01 19:47:50 +00005412 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005413 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005414
5415 /*
5416 Write pixels to memory.
5417 */
cristydd341db2010-03-04 19:06:38 +00005418 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005419 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005420 {
cristy48078b12010-09-23 17:11:01 +00005421 length=extent;
cristydd341db2010-03-04 19:06:38 +00005422 rows=1UL;
5423 }
cristyed231572011-07-14 02:18:59 +00005424 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005425 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005426 {
cristy8f036fe2010-09-18 02:02:00 +00005427 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005428 p+=nexus_info->region.width*cache_info->number_channels;
5429 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005430 }
5431 break;
5432 }
5433 case DiskCache:
5434 {
5435 /*
5436 Write pixels to disk.
5437 */
5438 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5439 {
5440 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5441 cache_info->cache_filename);
5442 return(MagickFalse);
5443 }
cristydd341db2010-03-04 19:06:38 +00005444 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005445 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005446 {
cristy48078b12010-09-23 17:11:01 +00005447 length=extent;
cristydd341db2010-03-04 19:06:38 +00005448 rows=1UL;
5449 }
cristybb503372010-05-27 20:51:26 +00005450 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005451 {
5452 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005453 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005454 p);
5455 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005456 break;
cristyed231572011-07-14 02:18:59 +00005457 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005458 offset+=cache_info->columns;
5459 }
cristyc11dace2012-01-24 16:39:46 +00005460 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5461 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005462 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005463 {
5464 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5465 cache_info->cache_filename);
5466 return(MagickFalse);
5467 }
5468 break;
5469 }
5470 default:
5471 break;
5472 }
5473 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005474 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005475 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005476 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005477 nexus_info->region.width,(double) nexus_info->region.height,(double)
5478 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005479 return(MagickTrue);
5480}