blob: 25abc1cd1609b32608ed4ed5174edc954d70ecb2 [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;
cristyd99b5a52012-10-27 23:07:47 +0000205 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
206 cache_info->number_threads=GetOpenMPMaximumThreads();
207 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
cristy9357bdd2012-07-30 12:28:34 +0000208 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
cristy134c76e2012-08-05 01:21:44 +0000209 if (cache_info->number_threads == 0)
210 cache_info->number_threads=1;
cristy3ed852e2009-09-05 21:47:34 +0000211 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
212 if (cache_info->nexus_info == (NexusInfo **) NULL)
213 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000214 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000215 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000216 cache_info->disk_semaphore=AllocateSemaphoreInfo();
217 cache_info->debug=IsEventLogging();
218 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000219 return((Cache ) cache_info);
220}
221
222/*
223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224% %
225% %
226% %
227% A c q u i r e P i x e l C a c h e N e x u s %
228% %
229% %
230% %
231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232%
233% AcquirePixelCacheNexus() allocates the NexusInfo structure.
234%
235% The format of the AcquirePixelCacheNexus method is:
236%
cristybb503372010-05-27 20:51:26 +0000237% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000238%
239% A description of each parameter follows:
240%
241% o number_threads: the number of nexus threads.
242%
243*/
cristya6577ff2011-09-02 19:54:26 +0000244MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000245{
cristy3ed852e2009-09-05 21:47:34 +0000246 NexusInfo
247 **nexus_info;
248
cristye076a6e2010-08-15 19:59:43 +0000249 register ssize_t
250 i;
251
cristye42639a2012-08-23 01:53:24 +0000252 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
253 number_threads,sizeof(*nexus_info)));
cristy3ed852e2009-09-05 21:47:34 +0000254 if (nexus_info == (NexusInfo **) NULL)
255 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000256 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
257 sizeof(**nexus_info));
258 if (nexus_info[0] == (NexusInfo *) NULL)
259 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
260 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
cristye5f87c82012-02-14 12:44:17 +0000263 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000264 nexus_info[i]->signature=MagickSignature;
265 }
266 return(nexus_info);
267}
268
269/*
270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271% %
272% %
273% %
cristyd43a46b2010-01-21 02:13:41 +0000274+ A c q u i r e P i x e l C a c h e P i x e l s %
275% %
276% %
277% %
278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279%
280% AcquirePixelCachePixels() returns the pixels associated with the specified
281% image.
282%
283% The format of the AcquirePixelCachePixels() method is:
284%
285% const void *AcquirePixelCachePixels(const Image *image,
286% MagickSizeType *length,ExceptionInfo *exception)
287%
288% A description of each parameter follows:
289%
290% o image: the image.
291%
292% o length: the pixel cache length.
293%
294% o exception: return any errors or warnings in this structure.
295%
296*/
cristyd1dd6e42011-09-04 01:46:08 +0000297MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000298 MagickSizeType *length,ExceptionInfo *exception)
299{
300 CacheInfo
301 *cache_info;
302
303 assert(image != (const Image *) NULL);
304 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000305 assert(exception != (ExceptionInfo *) NULL);
306 assert(exception->signature == MagickSignature);
307 assert(image->cache != (Cache) NULL);
308 cache_info=(CacheInfo *) image->cache;
309 assert(cache_info->signature == MagickSignature);
310 *length=0;
311 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
312 return((const void *) NULL);
313 *length=cache_info->length;
314 return((const void *) cache_info->pixels);
315}
316
317/*
318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319% %
320% %
321% %
cristyf34a1452009-10-24 22:29:27 +0000322+ C a c h e C o m p o n e n t G e n e s i s %
323% %
324% %
325% %
326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327%
328% CacheComponentGenesis() instantiates the cache component.
329%
330% The format of the CacheComponentGenesis method is:
331%
332% MagickBooleanType CacheComponentGenesis(void)
333%
334*/
cristy5ff4eaf2011-09-03 01:38:02 +0000335MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000336{
cristy165b6092009-10-26 13:52:10 +0000337 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000338 return(MagickTrue);
339}
340
341/*
342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343% %
344% %
345% %
346+ C a c h e C o m p o n e n t T e r m i n u s %
347% %
348% %
349% %
350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351%
352% CacheComponentTerminus() destroys the cache component.
353%
354% The format of the CacheComponentTerminus() method is:
355%
356% CacheComponentTerminus(void)
357%
358*/
cristy5ff4eaf2011-09-03 01:38:02 +0000359MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000360{
cristy18b17442009-10-25 18:36:48 +0000361 if (cache_semaphore == (SemaphoreInfo *) NULL)
362 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000363 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000364 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000365 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000366 DestroySemaphoreInfo(&cache_semaphore);
367}
368
369/*
370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371% %
372% %
373% %
cristy3ed852e2009-09-05 21:47:34 +0000374+ C l o n e P i x e l C a c h e %
375% %
376% %
377% %
378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379%
380% ClonePixelCache() clones a pixel cache.
381%
382% The format of the ClonePixelCache() method is:
383%
384% Cache ClonePixelCache(const Cache cache)
385%
386% A description of each parameter follows:
387%
388% o cache: the pixel cache.
389%
390*/
cristya6577ff2011-09-02 19:54:26 +0000391MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000392{
393 CacheInfo
394 *clone_info;
395
396 const CacheInfo
397 *cache_info;
398
cristy9f027d12011-09-21 01:17:17 +0000399 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000400 cache_info=(const CacheInfo *) cache;
401 assert(cache_info->signature == MagickSignature);
402 if (cache_info->debug != MagickFalse)
403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
404 cache_info->filename);
405 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
406 if (clone_info == (Cache) NULL)
407 return((Cache) NULL);
408 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
409 return((Cache ) clone_info);
410}
411
412/*
413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
414% %
415% %
416% %
cristy60c44a82009-10-07 00:58:49 +0000417+ 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 +0000418% %
419% %
420% %
421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
422% ClonePixelCachePixels() clones the source pixel cache to the destination
423% cache.
424%
425% The format of the ClonePixelCachePixels() method is:
426%
427% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
428% CacheInfo *source_info,ExceptionInfo *exception)
429%
430% A description of each parameter follows:
431%
432% o cache_info: the pixel cache.
433%
434% o source_info: the source pixel cache.
435%
436% o exception: return any errors or warnings in this structure.
437%
438*/
439
440static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
441{
442 int
443 status;
444
cristy5ee247a2010-02-12 15:42:34 +0000445 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000446 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000447 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000448 {
449 status=close(cache_info->file);
450 cache_info->file=(-1);
451 RelinquishMagickResource(FileResource,1);
452 }
cristyf84a1932010-01-03 18:00:18 +0000453 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000454 return(status == -1 ? MagickFalse : MagickTrue);
455}
456
cristy3ed852e2009-09-05 21:47:34 +0000457static inline MagickSizeType MagickMax(const MagickSizeType x,
458 const MagickSizeType y)
459{
460 if (x > y)
461 return(x);
462 return(y);
463}
464
465static inline MagickSizeType MagickMin(const MagickSizeType x,
466 const MagickSizeType y)
467{
468 if (x < y)
469 return(x);
470 return(y);
471}
472
473static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
474 const MapMode mode)
475{
476 int
477 file;
478
479 /*
480 Open pixel cache on disk.
481 */
cristyf84a1932010-01-03 18:00:18 +0000482 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000483 if (cache_info->file != -1)
484 {
cristyf84a1932010-01-03 18:00:18 +0000485 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000486 return(MagickTrue); /* cache already open */
487 }
cristy3ed852e2009-09-05 21:47:34 +0000488 if (*cache_info->cache_filename == '\0')
489 file=AcquireUniqueFileResource(cache_info->cache_filename);
490 else
491 switch (mode)
492 {
493 case ReadMode:
494 {
cristy18c6c272011-09-23 14:40:37 +0000495 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000496 break;
497 }
498 case WriteMode:
499 {
cristy18c6c272011-09-23 14:40:37 +0000500 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
501 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000502 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000503 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000504 break;
505 }
506 case IOMode:
507 default:
508 {
cristy18c6c272011-09-23 14:40:37 +0000509 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000510 O_EXCL,S_MODE);
511 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000512 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000513 break;
514 }
515 }
516 if (file == -1)
517 {
cristyf84a1932010-01-03 18:00:18 +0000518 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000519 return(MagickFalse);
520 }
521 (void) AcquireMagickResource(FileResource,1);
522 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000523 cache_info->mode=mode;
cristyf84a1932010-01-03 18:00:18 +0000524 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000525 return(MagickTrue);
526}
527
cristyf1832792012-05-08 18:38:18 +0000528static inline MagickOffsetType ReadPixelCacheRegion(
529 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
530 const MagickSizeType length,unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000531{
532 register MagickOffsetType
533 i;
534
535 ssize_t
536 count;
537
538#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000539 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000540 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000541 {
cristyf84a1932010-01-03 18:00:18 +0000542 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000543 return((MagickOffsetType) -1);
544 }
545#endif
546 count=0;
547 for (i=0; i < (MagickOffsetType) length; i+=count)
548 {
549#if !defined(MAGICKCORE_HAVE_PREAD)
550 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
551 (MagickSizeType) SSIZE_MAX));
552#else
553 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000554 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000555#endif
cristy0bcbb402012-10-21 00:55:09 +0000556 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000557 {
cristy0bcbb402012-10-21 00:55:09 +0000558 count=0;
559 if (errno != EINTR)
560 break;
cristy3ed852e2009-09-05 21:47:34 +0000561 }
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
cristy0bcbb402012-10-21 00:55:09 +0000597 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000598 {
cristy0bcbb402012-10-21 00:55:09 +0000599 count=0;
600 if (errno != EINTR)
601 break;
cristy3ed852e2009-09-05 21:47:34 +0000602 }
603 }
604#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000605 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000606#endif
607 return(i);
608}
609
cristy4c08aed2011-07-01 19:47:50 +0000610static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000611 CacheInfo *cache_info,ExceptionInfo *exception)
612{
613 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000614 count;
cristy3ed852e2009-09-05 21:47:34 +0000615
cristy4c08aed2011-07-01 19:47:50 +0000616 register MagickOffsetType
617 i;
cristye076a6e2010-08-15 19:59:43 +0000618
cristybb503372010-05-27 20:51:26 +0000619 size_t
cristy4c08aed2011-07-01 19:47:50 +0000620 length;
cristy3ed852e2009-09-05 21:47:34 +0000621
cristy4c08aed2011-07-01 19:47:50 +0000622 unsigned char
623 *blob;
624
625 /*
626 Clone pixel cache (both caches on disk).
627 */
cristy3ed852e2009-09-05 21:47:34 +0000628 if (cache_info->debug != MagickFalse)
629 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000630 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000631 sizeof(*blob));
632 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000633 {
cristy4c08aed2011-07-01 19:47:50 +0000634 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000635 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000636 cache_info->filename);
637 return(MagickFalse);
638 }
cristy3dedf062011-07-02 14:07:40 +0000639 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000640 {
641 blob=(unsigned char *) RelinquishMagickMemory(blob);
642 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
643 cache_info->cache_filename);
644 return(MagickFalse);
645 }
cristy3dedf062011-07-02 14:07:40 +0000646 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000647 {
648 (void) ClosePixelCacheOnDisk(cache_info);
649 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000650 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
651 clone_info->cache_filename);
652 return(MagickFalse);
653 }
cristy4c08aed2011-07-01 19:47:50 +0000654 count=0;
655 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000656 {
cristy4c08aed2011-07-01 19:47:50 +0000657 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
658 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
659 blob);
660 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000661 {
cristy4c08aed2011-07-01 19:47:50 +0000662 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
663 cache_info->cache_filename);
664 break;
cristy3ed852e2009-09-05 21:47:34 +0000665 }
cristy4c08aed2011-07-01 19:47:50 +0000666 length=(size_t) count;
667 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
668 if ((MagickSizeType) count != length)
669 {
670 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
671 clone_info->cache_filename);
672 break;
673 }
674 }
675 (void) ClosePixelCacheOnDisk(clone_info);
676 (void) ClosePixelCacheOnDisk(cache_info);
677 blob=(unsigned char *) RelinquishMagickMemory(blob);
678 if (i < (MagickOffsetType) cache_info->length)
679 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000680 return(MagickTrue);
681}
682
cristyfd24a062012-01-02 14:46:34 +0000683static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000684 CacheInfo *cache_info,ExceptionInfo *exception)
685{
686 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000687 count;
cristy3ed852e2009-09-05 21:47:34 +0000688
cristy4c08aed2011-07-01 19:47:50 +0000689 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000690 {
cristy3ed852e2009-09-05 21:47:34 +0000691 /*
cristy4c08aed2011-07-01 19:47:50 +0000692 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000693 */
cristy4c08aed2011-07-01 19:47:50 +0000694 if (cache_info->debug != MagickFalse)
695 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
696 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
697 cache_info->length);
698 return(MagickTrue);
699 }
700 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
701 {
702 /*
703 Clone pixel cache (one cache on disk, one in memory).
704 */
705 if (cache_info->debug != MagickFalse)
706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
707 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000708 {
cristy4c08aed2011-07-01 19:47:50 +0000709 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000710 cache_info->cache_filename);
711 return(MagickFalse);
712 }
cristy4c08aed2011-07-01 19:47:50 +0000713 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
714 cache_info->length,(unsigned char *) clone_info->pixels);
715 (void) ClosePixelCacheOnDisk(cache_info);
716 if ((MagickSizeType) count != cache_info->length)
717 {
718 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
719 cache_info->cache_filename);
720 return(MagickFalse);
721 }
722 return(MagickTrue);
723 }
724 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
725 {
726 /*
727 Clone pixel cache (one cache on disk, one in memory).
728 */
729 if (clone_info->debug != MagickFalse)
730 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
731 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
732 {
733 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
734 clone_info->cache_filename);
735 return(MagickFalse);
736 }
737 count=WritePixelCacheRegion(clone_info,clone_info->offset,
738 clone_info->length,(unsigned char *) cache_info->pixels);
739 (void) ClosePixelCacheOnDisk(clone_info);
740 if ((MagickSizeType) count != clone_info->length)
741 {
742 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
743 clone_info->cache_filename);
744 return(MagickFalse);
745 }
746 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000747 }
748 /*
cristy4c08aed2011-07-01 19:47:50 +0000749 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000750 */
cristy4c08aed2011-07-01 19:47:50 +0000751 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000752}
753
cristyfd24a062012-01-02 14:46:34 +0000754static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000755 CacheInfo *cache_info,ExceptionInfo *exception)
756{
cristy4c08aed2011-07-01 19:47:50 +0000757 MagickBooleanType
758 status;
cristy3ed852e2009-09-05 21:47:34 +0000759
cristy4c08aed2011-07-01 19:47:50 +0000760 MagickOffsetType
761 cache_offset,
762 clone_offset,
763 count;
764
765 register ssize_t
766 x;
767
cristyfd24a062012-01-02 14:46:34 +0000768 register unsigned char
769 *p;
770
cristy4c08aed2011-07-01 19:47:50 +0000771 size_t
cristy3ed852e2009-09-05 21:47:34 +0000772 length;
773
cristy4c08aed2011-07-01 19:47:50 +0000774 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000775 y;
776
cristy4c08aed2011-07-01 19:47:50 +0000777 unsigned char
778 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000779
cristy4c08aed2011-07-01 19:47:50 +0000780 /*
781 Clone pixel cache (unoptimized).
782 */
cristy3ed852e2009-09-05 21:47:34 +0000783 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000784 {
cristy4c08aed2011-07-01 19:47:50 +0000785 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
787 else
788 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
789 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
790 else
791 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
792 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
793 else
794 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
795 }
cristyed231572011-07-14 02:18:59 +0000796 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
797 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000798 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000799 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000800 if (blob == (unsigned char *) NULL)
801 {
802 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000803 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000804 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000805 return(MagickFalse);
806 }
cristy4c08aed2011-07-01 19:47:50 +0000807 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
808 cache_offset=0;
809 clone_offset=0;
810 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000811 {
cristy4c08aed2011-07-01 19:47:50 +0000812 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000813 {
cristy4c08aed2011-07-01 19:47:50 +0000814 blob=(unsigned char *) RelinquishMagickMemory(blob);
815 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000816 cache_info->cache_filename);
817 return(MagickFalse);
818 }
cristy4c08aed2011-07-01 19:47:50 +0000819 cache_offset=cache_info->offset;
820 }
821 if (clone_info->type == DiskCache)
822 {
cristy3dedf062011-07-02 14:07:40 +0000823 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000824 {
cristy4c08aed2011-07-01 19:47:50 +0000825 blob=(unsigned char *) RelinquishMagickMemory(blob);
826 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
827 clone_info->cache_filename);
828 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000829 }
cristy4c08aed2011-07-01 19:47:50 +0000830 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000831 }
832 /*
cristy4c08aed2011-07-01 19:47:50 +0000833 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000834 */
cristy4c08aed2011-07-01 19:47:50 +0000835 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000836 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000837 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000838 {
cristy4c08aed2011-07-01 19:47:50 +0000839 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000840 {
cristy9e0719b2011-12-29 03:45:45 +0000841 register ssize_t
842 i;
843
cristy3ed852e2009-09-05 21:47:34 +0000844 /*
cristy4c08aed2011-07-01 19:47:50 +0000845 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000846 */
cristyed231572011-07-14 02:18:59 +0000847 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000848 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000849 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000850 else
851 {
cristyfd24a062012-01-02 14:46:34 +0000852 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000853 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000854 {
cristy4c08aed2011-07-01 19:47:50 +0000855 status=MagickFalse;
856 break;
cristy3ed852e2009-09-05 21:47:34 +0000857 }
858 }
cristy4c08aed2011-07-01 19:47:50 +0000859 cache_offset+=length;
860 if ((y < (ssize_t) clone_info->rows) &&
861 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000862 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000863 {
cristy9e0719b2011-12-29 03:45:45 +0000864 PixelChannel
865 channel;
866
867 PixelTrait
868 traits;
869
870 ssize_t
871 offset;
872
cristy4c08aed2011-07-01 19:47:50 +0000873 /*
cristy3b8fe922011-12-29 18:56:23 +0000874 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000875 */
cristy9e0719b2011-12-29 03:45:45 +0000876 channel=clone_info->channel_map[i].channel;
877 traits=cache_info->channel_map[channel].traits;
878 if (traits == UndefinedPixelTrait)
879 {
cristy0f4425e2011-12-31 20:33:02 +0000880 clone_offset+=sizeof(Quantum);
881 continue;
cristy9e0719b2011-12-29 03:45:45 +0000882 }
cristy0f4425e2011-12-31 20:33:02 +0000883 offset=cache_info->channel_map[channel].offset;
884 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000885 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
886 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000887 else
888 {
cristy0f4425e2011-12-31 20:33:02 +0000889 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000890 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000891 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000892 {
cristy0f4425e2011-12-31 20:33:02 +0000893 status=MagickFalse;
894 break;
cristy4c08aed2011-07-01 19:47:50 +0000895 }
896 }
cristy9e0719b2011-12-29 03:45:45 +0000897 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000898 }
899 }
cristyac245f82012-05-05 17:13:57 +0000900 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000901 {
902 /*
903 Set remaining columns as undefined.
904 */
cristy888e6132012-04-23 19:54:54 +0000905 length=clone_info->number_channels*sizeof(Quantum);
906 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
907 for ( ; x < (ssize_t) clone_info->columns; x++)
908 {
909 if (clone_info->type != DiskCache)
910 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
911 blob,length);
912 else
913 {
914 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
915 if ((MagickSizeType) count != length)
916 {
917 status=MagickFalse;
918 break;
cristye04362f2012-04-23 15:33:05 +0000919 }
cristy888e6132012-04-23 19:54:54 +0000920 }
921 clone_offset+=length;
922 }
cristye04362f2012-04-23 15:33:05 +0000923 }
cristy4c08aed2011-07-01 19:47:50 +0000924 }
cristyed231572011-07-14 02:18:59 +0000925 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000926 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
927 for ( ; y < (ssize_t) clone_info->rows; y++)
928 {
929 /*
cristy9e0719b2011-12-29 03:45:45 +0000930 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000931 */
932 for (x=0; x < (ssize_t) clone_info->columns; x++)
933 {
934 if (clone_info->type != DiskCache)
935 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
936 length);
937 else
938 {
939 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
940 if ((MagickSizeType) count != length)
941 {
942 status=MagickFalse;
943 break;
944 }
945 }
946 clone_offset+=length;
947 }
948 }
cristy9e0719b2011-12-29 03:45:45 +0000949 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000950 (clone_info->metacontent_extent != 0))
951 {
952 /*
953 Clone metacontent.
954 */
955 for (y=0; y < (ssize_t) cache_info->rows; y++)
956 {
957 for (x=0; x < (ssize_t) cache_info->columns; x++)
958 {
959 /*
960 Read a set of metacontent.
961 */
962 length=cache_info->metacontent_extent;
963 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000964 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000965 else
966 {
cristyfd24a062012-01-02 14:46:34 +0000967 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000968 if ((MagickSizeType) count != length)
969 {
970 status=MagickFalse;
971 break;
972 }
973 }
974 cache_offset+=length;
975 if ((y < (ssize_t) clone_info->rows) &&
976 (x < (ssize_t) clone_info->columns))
977 {
978 /*
979 Write a set of metacontent.
980 */
981 length=clone_info->metacontent_extent;
982 if (clone_info->type != DiskCache)
983 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000984 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000985 else
986 {
cristyfd24a062012-01-02 14:46:34 +0000987 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000988 if ((MagickSizeType) count != length)
989 {
990 status=MagickFalse;
991 break;
992 }
993 }
994 clone_offset+=length;
995 }
996 }
997 length=clone_info->metacontent_extent;
998 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
999 for ( ; x < (ssize_t) clone_info->columns; x++)
1000 {
1001 /*
cristy9e0719b2011-12-29 03:45:45 +00001002 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001003 */
1004 if (clone_info->type != DiskCache)
1005 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1006 blob,length);
1007 else
1008 {
cristy208b1002011-08-07 18:51:50 +00001009 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001010 if ((MagickSizeType) count != length)
1011 {
1012 status=MagickFalse;
1013 break;
1014 }
1015 }
1016 clone_offset+=length;
1017 }
1018 }
cristyac245f82012-05-05 17:13:57 +00001019 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001020 {
cristye04362f2012-04-23 15:33:05 +00001021 /*
1022 Set remaining rows as undefined.
1023 */
cristy888e6132012-04-23 19:54:54 +00001024 length=clone_info->metacontent_extent;
1025 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1026 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001027 {
cristy888e6132012-04-23 19:54:54 +00001028 for (x=0; x < (ssize_t) clone_info->columns; x++)
1029 {
1030 if (clone_info->type != DiskCache)
1031 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1032 blob,length);
1033 else
1034 {
1035 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1036 blob);
1037 if ((MagickSizeType) count != length)
1038 {
1039 status=MagickFalse;
1040 break;
1041 }
1042 }
1043 clone_offset+=length;
1044 }
cristye04362f2012-04-23 15:33:05 +00001045 }
cristy4c08aed2011-07-01 19:47:50 +00001046 }
cristy4c08aed2011-07-01 19:47:50 +00001047 }
1048 if (clone_info->type == DiskCache)
1049 (void) ClosePixelCacheOnDisk(clone_info);
1050 if (cache_info->type == DiskCache)
1051 (void) ClosePixelCacheOnDisk(cache_info);
1052 blob=(unsigned char *) RelinquishMagickMemory(blob);
1053 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001054}
1055
1056static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1057 CacheInfo *cache_info,ExceptionInfo *exception)
1058{
cristy3dfccb22011-12-28 21:47:20 +00001059 PixelChannelMap
1060 *p,
1061 *q;
1062
cristy5a7fbfb2010-11-06 16:10:59 +00001063 if (cache_info->type == PingCache)
1064 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001065 p=cache_info->channel_map;
1066 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001067 if ((cache_info->columns == clone_info->columns) &&
1068 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001069 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001070 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001071 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001072 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1073 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001074}
1075
1076/*
1077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078% %
1079% %
1080% %
1081+ C l o n e P i x e l C a c h e M e t h o d s %
1082% %
1083% %
1084% %
1085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086%
1087% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1088% another.
1089%
1090% The format of the ClonePixelCacheMethods() method is:
1091%
1092% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1093%
1094% A description of each parameter follows:
1095%
1096% o clone: Specifies a pointer to a Cache structure.
1097%
1098% o cache: the pixel cache.
1099%
1100*/
cristya6577ff2011-09-02 19:54:26 +00001101MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001102{
1103 CacheInfo
1104 *cache_info,
1105 *source_info;
1106
1107 assert(clone != (Cache) NULL);
1108 source_info=(CacheInfo *) clone;
1109 assert(source_info->signature == MagickSignature);
1110 if (source_info->debug != MagickFalse)
1111 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1112 source_info->filename);
1113 assert(cache != (Cache) NULL);
1114 cache_info=(CacheInfo *) cache;
1115 assert(cache_info->signature == MagickSignature);
1116 source_info->methods=cache_info->methods;
1117}
1118
1119/*
1120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1121% %
1122% %
1123% %
1124+ D e s t r o y I m a g e P i x e l C a c h e %
1125% %
1126% %
1127% %
1128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1129%
1130% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1131%
1132% The format of the DestroyImagePixelCache() method is:
1133%
1134% void DestroyImagePixelCache(Image *image)
1135%
1136% A description of each parameter follows:
1137%
1138% o image: the image.
1139%
1140*/
1141static void DestroyImagePixelCache(Image *image)
1142{
1143 assert(image != (Image *) NULL);
1144 assert(image->signature == MagickSignature);
1145 if (image->debug != MagickFalse)
1146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1147 if (image->cache == (void *) NULL)
1148 return;
1149 image->cache=DestroyPixelCache(image->cache);
1150}
1151
1152/*
1153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1154% %
1155% %
1156% %
1157+ D e s t r o y I m a g e P i x e l s %
1158% %
1159% %
1160% %
1161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162%
1163% DestroyImagePixels() deallocates memory associated with the pixel cache.
1164%
1165% The format of the DestroyImagePixels() method is:
1166%
1167% void DestroyImagePixels(Image *image)
1168%
1169% A description of each parameter follows:
1170%
1171% o image: the image.
1172%
1173*/
1174MagickExport void DestroyImagePixels(Image *image)
1175{
1176 CacheInfo
1177 *cache_info;
1178
1179 assert(image != (const Image *) NULL);
1180 assert(image->signature == MagickSignature);
1181 if (image->debug != MagickFalse)
1182 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1183 assert(image->cache != (Cache) NULL);
1184 cache_info=(CacheInfo *) image->cache;
1185 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001186 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1187 {
1188 cache_info->methods.destroy_pixel_handler(image);
1189 return;
1190 }
cristy2036f5c2010-09-19 21:18:17 +00001191 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001192}
1193
1194/*
1195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1196% %
1197% %
1198% %
1199+ D e s t r o y P i x e l C a c h e %
1200% %
1201% %
1202% %
1203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1204%
1205% DestroyPixelCache() deallocates memory associated with the pixel cache.
1206%
1207% The format of the DestroyPixelCache() method is:
1208%
1209% Cache DestroyPixelCache(Cache cache)
1210%
1211% A description of each parameter follows:
1212%
1213% o cache: the pixel cache.
1214%
1215*/
1216
1217static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1218{
1219 switch (cache_info->type)
1220 {
1221 case MemoryCache:
1222 {
1223 if (cache_info->mapped == MagickFalse)
cristy9dd0b6f2012-08-01 14:38:43 +00001224 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
cristy3ed852e2009-09-05 21:47:34 +00001225 cache_info->pixels);
1226 else
cristy4c08aed2011-07-01 19:47:50 +00001227 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001228 (size_t) cache_info->length);
1229 RelinquishMagickResource(MemoryResource,cache_info->length);
1230 break;
1231 }
1232 case MapCache:
1233 {
cristy4c08aed2011-07-01 19:47:50 +00001234 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001235 cache_info->length);
1236 RelinquishMagickResource(MapResource,cache_info->length);
1237 }
1238 case DiskCache:
1239 {
1240 if (cache_info->file != -1)
1241 (void) ClosePixelCacheOnDisk(cache_info);
1242 RelinquishMagickResource(DiskResource,cache_info->length);
1243 break;
1244 }
1245 default:
1246 break;
1247 }
1248 cache_info->type=UndefinedCache;
1249 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001250 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001251}
1252
cristya6577ff2011-09-02 19:54:26 +00001253MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001254{
1255 CacheInfo
1256 *cache_info;
1257
cristy3ed852e2009-09-05 21:47:34 +00001258 assert(cache != (Cache) NULL);
1259 cache_info=(CacheInfo *) cache;
1260 assert(cache_info->signature == MagickSignature);
1261 if (cache_info->debug != MagickFalse)
1262 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1263 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001264 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001265 cache_info->reference_count--;
1266 if (cache_info->reference_count != 0)
1267 {
cristyf84a1932010-01-03 18:00:18 +00001268 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001269 return((Cache) NULL);
1270 }
cristyf84a1932010-01-03 18:00:18 +00001271 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001272 if (cache_info->debug != MagickFalse)
1273 {
1274 char
1275 message[MaxTextExtent];
1276
cristyb51dff52011-05-19 16:55:47 +00001277 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001278 cache_info->filename);
1279 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1280 }
cristyc2e1bdd2009-09-10 23:43:34 +00001281 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1282 (cache_info->type != DiskCache)))
1283 RelinquishPixelCachePixels(cache_info);
1284 else
1285 {
1286 RelinquishPixelCachePixels(cache_info);
1287 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1288 }
cristy3ed852e2009-09-05 21:47:34 +00001289 *cache_info->cache_filename='\0';
1290 if (cache_info->nexus_info != (NexusInfo **) NULL)
1291 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1292 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001293 if (cache_info->random_info != (RandomInfo *) NULL)
1294 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001295 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1296 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1297 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1298 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001299 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001300 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001301 cache=(Cache) NULL;
1302 return(cache);
1303}
1304
1305/*
1306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307% %
1308% %
1309% %
1310+ D e s t r o y P i x e l C a c h e N e x u s %
1311% %
1312% %
1313% %
1314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1315%
1316% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1317%
1318% The format of the DestroyPixelCacheNexus() method is:
1319%
1320% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001321% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001322%
1323% A description of each parameter follows:
1324%
1325% o nexus_info: the nexus to destroy.
1326%
1327% o number_threads: the number of nexus threads.
1328%
1329*/
1330
1331static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1332{
1333 if (nexus_info->mapped == MagickFalse)
cristy9dd0b6f2012-08-01 14:38:43 +00001334 (void) RelinquishAlignedMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001335 else
1336 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001337 nexus_info->cache=(Quantum *) NULL;
1338 nexus_info->pixels=(Quantum *) NULL;
1339 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001340 nexus_info->length=0;
1341 nexus_info->mapped=MagickFalse;
1342}
1343
cristya6577ff2011-09-02 19:54:26 +00001344MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001345 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001346{
cristybb503372010-05-27 20:51:26 +00001347 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001348 i;
1349
1350 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001351 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001352 {
cristy4c08aed2011-07-01 19:47:50 +00001353 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001354 RelinquishCacheNexusPixels(nexus_info[i]);
1355 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001356 }
cristye5f87c82012-02-14 12:44:17 +00001357 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001358 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001359 return(nexus_info);
1360}
1361
1362/*
1363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364% %
1365% %
1366% %
cristy4c08aed2011-07-01 19:47:50 +00001367% 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 +00001368% %
1369% %
1370% %
1371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372%
cristy4c08aed2011-07-01 19:47:50 +00001373% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1374% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1375% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001376%
cristy4c08aed2011-07-01 19:47:50 +00001377% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001378%
cristy4c08aed2011-07-01 19:47:50 +00001379% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001380%
1381% A description of each parameter follows:
1382%
1383% o image: the image.
1384%
1385*/
cristy4c08aed2011-07-01 19:47:50 +00001386MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001387{
1388 CacheInfo
1389 *cache_info;
1390
cristy5c9e6f22010-09-17 17:31:01 +00001391 const int
1392 id = GetOpenMPThreadId();
1393
cristy4c08aed2011-07-01 19:47:50 +00001394 void
1395 *metacontent;
1396
cristye7cc7cf2010-09-21 13:26:47 +00001397 assert(image != (const Image *) NULL);
1398 assert(image->signature == MagickSignature);
1399 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001400 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001401 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001402 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1403 (GetAuthenticMetacontentFromHandler) NULL)
1404 {
1405 metacontent=cache_info->methods.
1406 get_authentic_metacontent_from_handler(image);
1407 return(metacontent);
1408 }
cristy6ebe97c2010-07-03 01:17:28 +00001409 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001410 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1411 cache_info->nexus_info[id]);
1412 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001413}
1414
1415/*
1416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1417% %
1418% %
1419% %
cristy4c08aed2011-07-01 19:47:50 +00001420+ 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 +00001421% %
1422% %
1423% %
1424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1425%
cristy4c08aed2011-07-01 19:47:50 +00001426% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1427% with the last call to QueueAuthenticPixelsCache() or
1428% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001429%
cristy4c08aed2011-07-01 19:47:50 +00001430% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001431%
cristy4c08aed2011-07-01 19:47:50 +00001432% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001433%
1434% A description of each parameter follows:
1435%
1436% o image: the image.
1437%
1438*/
cristy4c08aed2011-07-01 19:47:50 +00001439static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001440{
1441 CacheInfo
1442 *cache_info;
1443
cristy2036f5c2010-09-19 21:18:17 +00001444 const int
1445 id = GetOpenMPThreadId();
1446
cristy4c08aed2011-07-01 19:47:50 +00001447 void
1448 *metacontent;
1449
cristy3ed852e2009-09-05 21:47:34 +00001450 assert(image != (const Image *) NULL);
1451 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001452 assert(image->cache != (Cache) NULL);
1453 cache_info=(CacheInfo *) image->cache;
1454 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001455 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001456 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1457 cache_info->nexus_info[id]);
1458 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001459}
1460
1461/*
1462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1463% %
1464% %
1465% %
1466+ 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 %
1467% %
1468% %
1469% %
1470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1471%
1472% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1473% disk pixel cache as defined by the geometry parameters. A pointer to the
1474% pixels is returned if the pixels are transferred, otherwise a NULL is
1475% returned.
1476%
1477% The format of the GetAuthenticPixelCacheNexus() method is:
1478%
cristy4c08aed2011-07-01 19:47:50 +00001479% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001480% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001481% NexusInfo *nexus_info,ExceptionInfo *exception)
1482%
1483% A description of each parameter follows:
1484%
1485% o image: the image.
1486%
1487% o x,y,columns,rows: These values define the perimeter of a region of
1488% pixels.
1489%
1490% o nexus_info: the cache nexus to return.
1491%
1492% o exception: return any errors or warnings in this structure.
1493%
1494*/
1495
cristy7f69b802012-05-08 16:39:59 +00001496static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001497 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001498{
cristy4c08aed2011-07-01 19:47:50 +00001499 MagickBooleanType
1500 status;
1501
cristy3ed852e2009-09-05 21:47:34 +00001502 MagickOffsetType
1503 offset;
1504
cristy73724512010-04-12 14:43:14 +00001505 if (cache_info->type == PingCache)
1506 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001507 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1508 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001509 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001510 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001511 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001512}
1513
cristya6577ff2011-09-02 19:54:26 +00001514MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001515 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001516 NexusInfo *nexus_info,ExceptionInfo *exception)
1517{
1518 CacheInfo
1519 *cache_info;
1520
cristy4c08aed2011-07-01 19:47:50 +00001521 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001522 *q;
cristy3ed852e2009-09-05 21:47:34 +00001523
1524 /*
1525 Transfer pixels from the cache.
1526 */
1527 assert(image != (Image *) NULL);
1528 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001529 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1530 exception);
cristyacd2ed22011-08-30 01:44:23 +00001531 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001532 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001533 cache_info=(CacheInfo *) image->cache;
1534 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001535 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001536 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001537 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001538 return((Quantum *) NULL);
1539 if (cache_info->metacontent_extent != 0)
1540 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1541 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001542 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001543}
1544
1545/*
1546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547% %
1548% %
1549% %
1550+ 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 %
1551% %
1552% %
1553% %
1554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555%
1556% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1557% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1558%
1559% The format of the GetAuthenticPixelsFromCache() method is:
1560%
cristy4c08aed2011-07-01 19:47:50 +00001561% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001562%
1563% A description of each parameter follows:
1564%
1565% o image: the image.
1566%
1567*/
cristy4c08aed2011-07-01 19:47:50 +00001568static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001569{
1570 CacheInfo
1571 *cache_info;
1572
cristy5c9e6f22010-09-17 17:31:01 +00001573 const int
1574 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001575
cristye7cc7cf2010-09-21 13:26:47 +00001576 assert(image != (const Image *) NULL);
1577 assert(image->signature == MagickSignature);
1578 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001579 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001580 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001581 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001582 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001583}
1584
1585/*
1586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587% %
1588% %
1589% %
1590% G e t A u t h e n t i c P i x e l Q u e u e %
1591% %
1592% %
1593% %
1594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595%
cristy4c08aed2011-07-01 19:47:50 +00001596% GetAuthenticPixelQueue() returns the authentic pixels associated
1597% corresponding with the last call to QueueAuthenticPixels() or
1598% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001599%
1600% The format of the GetAuthenticPixelQueue() method is:
1601%
cristy4c08aed2011-07-01 19:47:50 +00001602% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001603%
1604% A description of each parameter follows:
1605%
1606% o image: the image.
1607%
1608*/
cristy4c08aed2011-07-01 19:47:50 +00001609MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001610{
1611 CacheInfo
1612 *cache_info;
1613
cristy2036f5c2010-09-19 21:18:17 +00001614 const int
1615 id = GetOpenMPThreadId();
1616
cristy3ed852e2009-09-05 21:47:34 +00001617 assert(image != (const Image *) NULL);
1618 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001619 assert(image->cache != (Cache) NULL);
1620 cache_info=(CacheInfo *) image->cache;
1621 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001622 if (cache_info->methods.get_authentic_pixels_from_handler !=
1623 (GetAuthenticPixelsFromHandler) NULL)
1624 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001625 assert(id < (int) cache_info->number_threads);
1626 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001627}
1628
1629/*
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631% %
1632% %
1633% %
1634% G e t A u t h e n t i c P i x e l s %
1635% %
1636% %
cristy4c08aed2011-07-01 19:47:50 +00001637% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001638%
1639% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001640% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001641% representing the region is returned, otherwise NULL is returned.
1642%
1643% The returned pointer may point to a temporary working copy of the pixels
1644% or it may point to the original pixels in memory. Performance is maximized
1645% if the selected region is part of one row, or one or more full rows, since
1646% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001647% if the image is in memory, or in a memory-mapped file. The returned pointer
1648% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001649%
1650% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001651% Quantum. If the image has corresponding metacontent,call
1652% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1653% meta-content corresponding to the region. Once the Quantum array has
1654% been updated, the changes must be saved back to the underlying image using
1655% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001656%
1657% The format of the GetAuthenticPixels() method is:
1658%
cristy4c08aed2011-07-01 19:47:50 +00001659% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001660% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001661% ExceptionInfo *exception)
1662%
1663% A description of each parameter follows:
1664%
1665% o image: the image.
1666%
1667% o x,y,columns,rows: These values define the perimeter of a region of
1668% pixels.
1669%
1670% o exception: return any errors or warnings in this structure.
1671%
1672*/
cristy4c08aed2011-07-01 19:47:50 +00001673MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001674 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001675 ExceptionInfo *exception)
1676{
1677 CacheInfo
1678 *cache_info;
1679
cristy2036f5c2010-09-19 21:18:17 +00001680 const int
1681 id = GetOpenMPThreadId();
1682
cristy4c08aed2011-07-01 19:47:50 +00001683 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001684 *q;
cristy4c08aed2011-07-01 19:47:50 +00001685
cristy3ed852e2009-09-05 21:47:34 +00001686 assert(image != (Image *) NULL);
1687 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001688 assert(image->cache != (Cache) NULL);
1689 cache_info=(CacheInfo *) image->cache;
1690 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001691 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001692 (GetAuthenticPixelsHandler) NULL)
1693 {
cristyacd2ed22011-08-30 01:44:23 +00001694 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1695 exception);
1696 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001697 }
cristy2036f5c2010-09-19 21:18:17 +00001698 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001699 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001700 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001701 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001702}
1703
1704/*
1705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1706% %
1707% %
1708% %
1709+ G e t A u t h e n t i c P i x e l s C a c h e %
1710% %
1711% %
1712% %
1713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1714%
1715% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1716% as defined by the geometry parameters. A pointer to the pixels is returned
1717% if the pixels are transferred, otherwise a NULL is returned.
1718%
1719% The format of the GetAuthenticPixelsCache() method is:
1720%
cristy4c08aed2011-07-01 19:47:50 +00001721% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001722% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001723% ExceptionInfo *exception)
1724%
1725% A description of each parameter follows:
1726%
1727% o image: the image.
1728%
1729% o x,y,columns,rows: These values define the perimeter of a region of
1730% pixels.
1731%
1732% o exception: return any errors or warnings in this structure.
1733%
1734*/
cristy4c08aed2011-07-01 19:47:50 +00001735static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001736 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001737 ExceptionInfo *exception)
1738{
1739 CacheInfo
1740 *cache_info;
1741
cristy5c9e6f22010-09-17 17:31:01 +00001742 const int
1743 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001744
cristy4c08aed2011-07-01 19:47:50 +00001745 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001746 *q;
cristy4c08aed2011-07-01 19:47:50 +00001747
cristye7cc7cf2010-09-21 13:26:47 +00001748 assert(image != (const Image *) NULL);
1749 assert(image->signature == MagickSignature);
1750 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001751 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001752 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001753 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001754 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001755 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001756 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001757 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001758 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001759}
1760
1761/*
1762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763% %
1764% %
1765% %
1766+ G e t I m a g e E x t e n t %
1767% %
1768% %
1769% %
1770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1771%
cristy4c08aed2011-07-01 19:47:50 +00001772% GetImageExtent() returns the extent of the pixels associated corresponding
1773% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001774%
1775% The format of the GetImageExtent() method is:
1776%
1777% MagickSizeType GetImageExtent(const Image *image)
1778%
1779% A description of each parameter follows:
1780%
1781% o image: the image.
1782%
1783*/
1784MagickExport MagickSizeType GetImageExtent(const Image *image)
1785{
1786 CacheInfo
1787 *cache_info;
1788
cristy5c9e6f22010-09-17 17:31:01 +00001789 const int
1790 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001791
cristy3ed852e2009-09-05 21:47:34 +00001792 assert(image != (Image *) NULL);
1793 assert(image->signature == MagickSignature);
1794 if (image->debug != MagickFalse)
1795 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1796 assert(image->cache != (Cache) NULL);
1797 cache_info=(CacheInfo *) image->cache;
1798 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001799 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001800 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001801}
1802
1803/*
1804%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1805% %
1806% %
1807% %
1808+ G e t I m a g e P i x e l C a c h e %
1809% %
1810% %
1811% %
1812%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1813%
1814% GetImagePixelCache() ensures that there is only a single reference to the
1815% pixel cache to be modified, updating the provided cache pointer to point to
1816% a clone of the original pixel cache if necessary.
1817%
1818% The format of the GetImagePixelCache method is:
1819%
1820% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1821% ExceptionInfo *exception)
1822%
1823% A description of each parameter follows:
1824%
1825% o image: the image.
1826%
1827% o clone: any value other than MagickFalse clones the cache pixels.
1828%
1829% o exception: return any errors or warnings in this structure.
1830%
1831*/
cristyaf894d72011-08-06 23:03:10 +00001832
cristyf1832792012-05-08 18:38:18 +00001833static inline MagickBooleanType ValidatePixelCacheMorphology(
1834 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001835{
cristyf1832792012-05-08 18:38:18 +00001836 const CacheInfo
1837 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001838
cristyf1832792012-05-08 18:38:18 +00001839 const PixelChannelMap
1840 *restrict p,
1841 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001842
cristy3ed852e2009-09-05 21:47:34 +00001843 /*
1844 Does the image match the pixel cache morphology?
1845 */
1846 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001847 p=image->channel_map;
1848 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001849 if ((image->storage_class != cache_info->storage_class) ||
1850 (image->colorspace != cache_info->colorspace) ||
cristy8a46d822012-08-28 23:32:39 +00001851 (image->alpha_trait != cache_info->alpha_trait) ||
cristy183a5c72012-01-30 01:40:35 +00001852 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001853 (image->columns != cache_info->columns) ||
1854 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001855 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001856 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001857 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001858 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001859 return(MagickFalse);
1860 return(MagickTrue);
1861}
1862
cristycd01fae2011-08-06 23:52:42 +00001863static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1864 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001865{
1866 CacheInfo
1867 *cache_info;
1868
cristy3ed852e2009-09-05 21:47:34 +00001869 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001870 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001871 status;
1872
cristy50a10922010-02-15 18:35:25 +00001873 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001874 cpu_throttle = 0,
1875 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001876 time_limit = 0;
1877
cristy1ea34962010-07-01 19:49:21 +00001878 static time_t
cristy208b1002011-08-07 18:51:50 +00001879 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001880
cristyc4f9f132010-03-04 18:50:01 +00001881 status=MagickTrue;
1882 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001883 if (cpu_throttle == 0)
1884 {
1885 char
1886 *limit;
1887
1888 /*
1889 Set CPU throttle in milleseconds.
1890 */
1891 cpu_throttle=MagickResourceInfinity;
1892 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1893 if (limit == (char *) NULL)
1894 limit=GetPolicyValue("throttle");
1895 if (limit != (char *) NULL)
1896 {
1897 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1898 limit=DestroyString(limit);
1899 }
1900 }
1901 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1902 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001903 if (time_limit == 0)
1904 {
cristy6ebe97c2010-07-03 01:17:28 +00001905 /*
cristy3a8401e2012-10-29 22:01:37 +00001906 Set the expire time in seconds.
cristy6ebe97c2010-07-03 01:17:28 +00001907 */
cristy1ea34962010-07-01 19:49:21 +00001908 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001909 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001910 }
1911 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001912 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001913 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001914 assert(image->cache != (Cache) NULL);
1915 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001916 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001917 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001918 {
cristyceb55ee2010-11-06 16:05:49 +00001919 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001920 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001921 {
cristyceb55ee2010-11-06 16:05:49 +00001922 CacheInfo
1923 *clone_info;
1924
cristya28c61e2012-10-29 22:03:42 +00001925 Image
1926 clone_image;
1927
cristyceb55ee2010-11-06 16:05:49 +00001928 /*
1929 Clone pixel cache.
1930 */
1931 clone_image=(*image);
1932 clone_image.semaphore=AllocateSemaphoreInfo();
1933 clone_image.reference_count=1;
1934 clone_image.cache=ClonePixelCache(cache_info);
1935 clone_info=(CacheInfo *) clone_image.cache;
1936 status=OpenPixelCache(&clone_image,IOMode,exception);
1937 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001938 {
cristy5a7fbfb2010-11-06 16:10:59 +00001939 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001940 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001941 if (status != MagickFalse)
1942 {
cristye71be1b2012-10-28 20:10:06 +00001943 if (cache_info->mode == ReadMode)
1944 {
1945 cache_info->nexus_info=AcquirePixelCacheNexus(
1946 cache_info->number_threads);
1947 if (cache_info->nexus_info == (NexusInfo **) NULL)
1948 ThrowFatalException(ResourceLimitFatalError,
1949 "MemoryAllocationFailed");
1950 }
cristyceb55ee2010-11-06 16:05:49 +00001951 destroy=MagickTrue;
1952 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001953 }
1954 }
cristyceb55ee2010-11-06 16:05:49 +00001955 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001956 }
cristyceb55ee2010-11-06 16:05:49 +00001957 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001958 }
cristy4320e0e2009-09-10 15:00:08 +00001959 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001960 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001961 if (status != MagickFalse)
1962 {
1963 /*
1964 Ensure the image matches the pixel cache morphology.
1965 */
1966 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001967 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001968 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001969 {
1970 status=OpenPixelCache(image,IOMode,exception);
1971 cache_info=(CacheInfo *) image->cache;
1972 if (cache_info->type == DiskCache)
1973 (void) ClosePixelCacheOnDisk(cache_info);
1974 }
cristy3ed852e2009-09-05 21:47:34 +00001975 }
cristyf84a1932010-01-03 18:00:18 +00001976 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001977 if (status == MagickFalse)
1978 return((Cache) NULL);
1979 return(image->cache);
1980}
1981
1982/*
1983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1984% %
1985% %
1986% %
cristyce1fe792012-05-16 15:58:37 +00001987+ G e t I m a g e P i x e l C a c h e T y p e %
1988% %
1989% %
1990% %
1991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1992%
1993% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1994% DiskCache, MemoryCache, MapCache, or PingCache.
1995%
1996% The format of the GetImagePixelCacheType() method is:
1997%
cristy5bef4cd2012-05-17 18:08:56 +00001998% CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001999%
2000% A description of each parameter follows:
2001%
2002% o image: the image.
2003%
2004*/
cristy5bef4cd2012-05-17 18:08:56 +00002005MagickExport CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00002006{
cristy238287d2012-05-17 18:16:56 +00002007 CacheInfo
2008 *cache_info;
2009
2010 assert(image != (Image *) NULL);
2011 assert(image->signature == MagickSignature);
2012 assert(image->cache != (Cache) NULL);
2013 cache_info=(CacheInfo *) image->cache;
2014 assert(cache_info->signature == MagickSignature);
2015 return(cache_info->type);
cristyce1fe792012-05-16 15:58:37 +00002016}
2017
2018/*
2019%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2020% %
2021% %
2022% %
cristy3ed852e2009-09-05 21:47:34 +00002023% G e t O n e A u t h e n t i c P i x e l %
2024% %
2025% %
2026% %
2027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2028%
2029% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2030% location. The image background color is returned if an error occurs.
2031%
2032% The format of the GetOneAuthenticPixel() method is:
2033%
cristybb503372010-05-27 20:51:26 +00002034% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002035% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002036%
2037% A description of each parameter follows:
2038%
2039% o image: the image.
2040%
2041% o x,y: These values define the location of the pixel to return.
2042%
2043% o pixel: return a pixel at the specified (x,y) location.
2044%
2045% o exception: return any errors or warnings in this structure.
2046%
2047*/
cristyacbbb7c2010-06-30 18:56:48 +00002048MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002049 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002050{
2051 CacheInfo
2052 *cache_info;
2053
cristy4c08aed2011-07-01 19:47:50 +00002054 register Quantum
2055 *q;
cristy2036f5c2010-09-19 21:18:17 +00002056
cristy2ed42f62011-10-02 19:49:57 +00002057 register ssize_t
2058 i;
2059
cristy3ed852e2009-09-05 21:47:34 +00002060 assert(image != (Image *) NULL);
2061 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002062 assert(image->cache != (Cache) NULL);
2063 cache_info=(CacheInfo *) image->cache;
2064 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002065 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002066 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2067 (GetOneAuthenticPixelFromHandler) NULL)
2068 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2069 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002070 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2071 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002072 {
cristy9e0719b2011-12-29 03:45:45 +00002073 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2074 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2075 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2076 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2077 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002078 return(MagickFalse);
2079 }
2080 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2081 {
2082 PixelChannel
2083 channel;
2084
cristycf1296e2012-08-26 23:40:49 +00002085 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002086 pixel[channel]=q[i];
2087 }
cristy2036f5c2010-09-19 21:18:17 +00002088 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002089}
2090
2091/*
2092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2093% %
2094% %
2095% %
2096+ 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 %
2097% %
2098% %
2099% %
2100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2101%
2102% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2103% location. The image background color is returned if an error occurs.
2104%
2105% The format of the GetOneAuthenticPixelFromCache() method is:
2106%
2107% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002108% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002109% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002110%
2111% A description of each parameter follows:
2112%
2113% o image: the image.
2114%
2115% o x,y: These values define the location of the pixel to return.
2116%
2117% o pixel: return a pixel at the specified (x,y) location.
2118%
2119% o exception: return any errors or warnings in this structure.
2120%
2121*/
2122static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002123 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002124{
cristy098f78c2010-09-23 17:28:44 +00002125 CacheInfo
2126 *cache_info;
2127
2128 const int
2129 id = GetOpenMPThreadId();
2130
cristy4c08aed2011-07-01 19:47:50 +00002131 register Quantum
2132 *q;
cristy3ed852e2009-09-05 21:47:34 +00002133
cristy2ed42f62011-10-02 19:49:57 +00002134 register ssize_t
2135 i;
2136
cristy0158a4b2010-09-20 13:59:45 +00002137 assert(image != (const Image *) NULL);
2138 assert(image->signature == MagickSignature);
2139 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002140 cache_info=(CacheInfo *) image->cache;
2141 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002142 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002143 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002144 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2145 exception);
2146 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002147 {
cristy9e0719b2011-12-29 03:45:45 +00002148 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2149 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2150 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2151 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2152 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002153 return(MagickFalse);
2154 }
2155 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2156 {
2157 PixelChannel
2158 channel;
2159
cristycf1296e2012-08-26 23:40:49 +00002160 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002161 pixel[channel]=q[i];
2162 }
cristy3ed852e2009-09-05 21:47:34 +00002163 return(MagickTrue);
2164}
2165
2166/*
2167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2168% %
2169% %
2170% %
cristy3ed852e2009-09-05 21:47:34 +00002171% G e t O n e V i r t u a l P i x e l %
2172% %
2173% %
2174% %
2175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2176%
2177% GetOneVirtualPixel() returns a single virtual pixel at the specified
2178% (x,y) location. The image background color is returned if an error occurs.
2179% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2180%
2181% The format of the GetOneVirtualPixel() method is:
2182%
cristybb503372010-05-27 20:51:26 +00002183% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002184% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002185%
2186% A description of each parameter follows:
2187%
2188% o image: the image.
2189%
2190% o x,y: These values define the location of the pixel to return.
2191%
2192% o pixel: return a pixel at the specified (x,y) location.
2193%
2194% o exception: return any errors or warnings in this structure.
2195%
2196*/
2197MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002198 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002199{
cristy3ed852e2009-09-05 21:47:34 +00002200 CacheInfo
2201 *cache_info;
2202
cristy0158a4b2010-09-20 13:59:45 +00002203 const int
2204 id = GetOpenMPThreadId();
2205
cristy4c08aed2011-07-01 19:47:50 +00002206 const Quantum
2207 *p;
cristy2036f5c2010-09-19 21:18:17 +00002208
cristy2ed42f62011-10-02 19:49:57 +00002209 register ssize_t
2210 i;
2211
cristy3ed852e2009-09-05 21:47:34 +00002212 assert(image != (const Image *) NULL);
2213 assert(image->signature == MagickSignature);
2214 assert(image->cache != (Cache) NULL);
2215 cache_info=(CacheInfo *) image->cache;
2216 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002217 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002218 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2219 (GetOneVirtualPixelFromHandler) NULL)
2220 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2221 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002222 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002223 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002224 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002225 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002226 {
cristy9e0719b2011-12-29 03:45:45 +00002227 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2228 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2229 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2230 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2231 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002232 return(MagickFalse);
2233 }
2234 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2235 {
2236 PixelChannel
2237 channel;
2238
cristycf1296e2012-08-26 23:40:49 +00002239 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002240 pixel[channel]=p[i];
2241 }
cristy2036f5c2010-09-19 21:18:17 +00002242 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002243}
2244
2245/*
2246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247% %
2248% %
2249% %
2250+ 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 %
2251% %
2252% %
2253% %
2254%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2255%
2256% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2257% specified (x,y) location. The image background color is returned if an
2258% error occurs.
2259%
2260% The format of the GetOneVirtualPixelFromCache() method is:
2261%
2262% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002263% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002264% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002265%
2266% A description of each parameter follows:
2267%
2268% o image: the image.
2269%
2270% o virtual_pixel_method: the virtual pixel method.
2271%
2272% o x,y: These values define the location of the pixel to return.
2273%
2274% o pixel: return a pixel at the specified (x,y) location.
2275%
2276% o exception: return any errors or warnings in this structure.
2277%
2278*/
2279static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002280 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002281 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002282{
cristy0158a4b2010-09-20 13:59:45 +00002283 CacheInfo
2284 *cache_info;
2285
2286 const int
2287 id = GetOpenMPThreadId();
2288
cristy4c08aed2011-07-01 19:47:50 +00002289 const Quantum
2290 *p;
cristy3ed852e2009-09-05 21:47:34 +00002291
cristy2ed42f62011-10-02 19:49:57 +00002292 register ssize_t
2293 i;
2294
cristye7cc7cf2010-09-21 13:26:47 +00002295 assert(image != (const Image *) NULL);
2296 assert(image->signature == MagickSignature);
2297 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002298 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002299 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002300 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002301 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002302 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002303 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002304 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002305 {
cristy9e0719b2011-12-29 03:45:45 +00002306 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2307 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2308 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2309 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2310 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002311 return(MagickFalse);
2312 }
2313 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2314 {
2315 PixelChannel
2316 channel;
2317
cristycf1296e2012-08-26 23:40:49 +00002318 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002319 pixel[channel]=p[i];
2320 }
cristy3ed852e2009-09-05 21:47:34 +00002321 return(MagickTrue);
2322}
2323
2324/*
2325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2326% %
2327% %
2328% %
cristy3aa93752011-12-18 15:54:24 +00002329% G e t O n e V i r t u a l P i x e l I n f o %
2330% %
2331% %
2332% %
2333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2334%
2335% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2336% location. The image background color is returned if an error occurs. If
2337% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2338%
2339% The format of the GetOneVirtualPixelInfo() method is:
2340%
2341% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2342% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2343% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2344%
2345% A description of each parameter follows:
2346%
2347% o image: the image.
2348%
2349% o virtual_pixel_method: the virtual pixel method.
2350%
2351% o x,y: these values define the location of the pixel to return.
2352%
2353% o pixel: return a pixel at the specified (x,y) location.
2354%
2355% o exception: return any errors or warnings in this structure.
2356%
2357*/
2358MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2359 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2360 PixelInfo *pixel,ExceptionInfo *exception)
2361{
2362 CacheInfo
2363 *cache_info;
2364
2365 const int
2366 id = GetOpenMPThreadId();
2367
2368 register const Quantum
2369 *p;
2370
2371 assert(image != (const Image *) NULL);
2372 assert(image->signature == MagickSignature);
2373 assert(image->cache != (Cache) NULL);
2374 cache_info=(CacheInfo *) image->cache;
2375 assert(cache_info->signature == MagickSignature);
2376 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002377 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002378 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2379 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002380 if (p == (const Quantum *) NULL)
2381 return(MagickFalse);
2382 GetPixelInfoPixel(image,p,pixel);
2383 return(MagickTrue);
2384}
2385
2386/*
2387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388% %
2389% %
2390% %
cristy3ed852e2009-09-05 21:47:34 +00002391+ G e t P i x e l C a c h e C o l o r s p a c e %
2392% %
2393% %
2394% %
2395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2396%
2397% GetPixelCacheColorspace() returns the class type of the pixel cache.
2398%
2399% The format of the GetPixelCacheColorspace() method is:
2400%
2401% Colorspace GetPixelCacheColorspace(Cache cache)
2402%
2403% A description of each parameter follows:
2404%
2405% o cache: the pixel cache.
2406%
2407*/
cristya6577ff2011-09-02 19:54:26 +00002408MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002409{
2410 CacheInfo
2411 *cache_info;
2412
2413 assert(cache != (Cache) NULL);
2414 cache_info=(CacheInfo *) cache;
2415 assert(cache_info->signature == MagickSignature);
2416 if (cache_info->debug != MagickFalse)
2417 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2418 cache_info->filename);
2419 return(cache_info->colorspace);
2420}
2421
2422/*
2423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2424% %
2425% %
2426% %
2427+ G e t P i x e l C a c h e M e t h o d s %
2428% %
2429% %
2430% %
2431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2432%
2433% GetPixelCacheMethods() initializes the CacheMethods structure.
2434%
2435% The format of the GetPixelCacheMethods() method is:
2436%
2437% void GetPixelCacheMethods(CacheMethods *cache_methods)
2438%
2439% A description of each parameter follows:
2440%
2441% o cache_methods: Specifies a pointer to a CacheMethods structure.
2442%
2443*/
cristya6577ff2011-09-02 19:54:26 +00002444MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002445{
2446 assert(cache_methods != (CacheMethods *) NULL);
2447 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2448 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2449 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002450 cache_methods->get_virtual_metacontent_from_handler=
2451 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002452 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2453 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002454 cache_methods->get_authentic_metacontent_from_handler=
2455 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002456 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2457 cache_methods->get_one_authentic_pixel_from_handler=
2458 GetOneAuthenticPixelFromCache;
2459 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2460 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2461 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2462}
2463
2464/*
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466% %
2467% %
2468% %
2469+ G e t P i x e l C a c h e N e x u s E x t e n t %
2470% %
2471% %
2472% %
2473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474%
cristy4c08aed2011-07-01 19:47:50 +00002475% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2476% corresponding with the last call to SetPixelCacheNexusPixels() or
2477% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002478%
2479% The format of the GetPixelCacheNexusExtent() method is:
2480%
2481% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2482% NexusInfo *nexus_info)
2483%
2484% A description of each parameter follows:
2485%
2486% o nexus_info: the nexus info.
2487%
2488*/
cristya6577ff2011-09-02 19:54:26 +00002489MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002490 NexusInfo *nexus_info)
2491{
2492 CacheInfo
2493 *cache_info;
2494
2495 MagickSizeType
2496 extent;
2497
cristy9f027d12011-09-21 01:17:17 +00002498 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002499 cache_info=(CacheInfo *) cache;
2500 assert(cache_info->signature == MagickSignature);
2501 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2502 if (extent == 0)
2503 return((MagickSizeType) cache_info->columns*cache_info->rows);
2504 return(extent);
2505}
2506
2507/*
2508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2509% %
2510% %
2511% %
cristy4c08aed2011-07-01 19:47:50 +00002512+ 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 +00002513% %
2514% %
2515% %
2516%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2517%
cristy4c08aed2011-07-01 19:47:50 +00002518% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2519% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002520%
cristy4c08aed2011-07-01 19:47:50 +00002521% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002522%
cristy4c08aed2011-07-01 19:47:50 +00002523% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002524% NexusInfo *nexus_info)
2525%
2526% A description of each parameter follows:
2527%
2528% o cache: the pixel cache.
2529%
cristy4c08aed2011-07-01 19:47:50 +00002530% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002531%
2532*/
cristya6577ff2011-09-02 19:54:26 +00002533MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002534 NexusInfo *nexus_info)
2535{
2536 CacheInfo
2537 *cache_info;
2538
cristy9f027d12011-09-21 01:17:17 +00002539 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002540 cache_info=(CacheInfo *) cache;
2541 assert(cache_info->signature == MagickSignature);
2542 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002543 return((void *) NULL);
2544 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002545}
2546
2547/*
2548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549% %
2550% %
2551% %
2552+ G e t P i x e l C a c h e N e x u s P i x e l s %
2553% %
2554% %
2555% %
2556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2557%
2558% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2559% cache nexus.
2560%
2561% The format of the GetPixelCacheNexusPixels() method is:
2562%
cristy4c08aed2011-07-01 19:47:50 +00002563% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002564% NexusInfo *nexus_info)
2565%
2566% A description of each parameter follows:
2567%
2568% o cache: the pixel cache.
2569%
2570% o nexus_info: the cache nexus to return the pixels.
2571%
2572*/
cristya6577ff2011-09-02 19:54:26 +00002573MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002574 NexusInfo *nexus_info)
2575{
2576 CacheInfo
2577 *cache_info;
2578
cristy9f027d12011-09-21 01:17:17 +00002579 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002580 cache_info=(CacheInfo *) cache;
2581 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002582 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002583 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002584 return(nexus_info->pixels);
2585}
2586
2587/*
2588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2589% %
2590% %
2591% %
cristy056ba772010-01-02 23:33:54 +00002592+ G e t P i x e l C a c h e P i x e l s %
2593% %
2594% %
2595% %
2596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2597%
2598% GetPixelCachePixels() returns the pixels associated with the specified image.
2599%
2600% The format of the GetPixelCachePixels() method is:
2601%
cristyf84a1932010-01-03 18:00:18 +00002602% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2603% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002604%
2605% A description of each parameter follows:
2606%
2607% o image: the image.
2608%
2609% o length: the pixel cache length.
2610%
cristyf84a1932010-01-03 18:00:18 +00002611% o exception: return any errors or warnings in this structure.
2612%
cristy056ba772010-01-02 23:33:54 +00002613*/
cristyd1dd6e42011-09-04 01:46:08 +00002614MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002615 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002616{
2617 CacheInfo
2618 *cache_info;
2619
2620 assert(image != (const Image *) NULL);
2621 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002622 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002623 assert(length != (MagickSizeType *) NULL);
2624 assert(exception != (ExceptionInfo *) NULL);
2625 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002626 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002627 assert(cache_info->signature == MagickSignature);
2628 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002629 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002630 return((void *) NULL);
2631 *length=cache_info->length;
2632 return((void *) cache_info->pixels);
2633}
2634
2635/*
2636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2637% %
2638% %
2639% %
cristyb32b90a2009-09-07 21:45:48 +00002640+ 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 +00002641% %
2642% %
2643% %
2644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2645%
2646% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2647%
2648% The format of the GetPixelCacheStorageClass() method is:
2649%
2650% ClassType GetPixelCacheStorageClass(Cache cache)
2651%
2652% A description of each parameter follows:
2653%
2654% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2655%
2656% o cache: the pixel cache.
2657%
2658*/
cristya6577ff2011-09-02 19:54:26 +00002659MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002660{
2661 CacheInfo
2662 *cache_info;
2663
2664 assert(cache != (Cache) NULL);
2665 cache_info=(CacheInfo *) cache;
2666 assert(cache_info->signature == MagickSignature);
2667 if (cache_info->debug != MagickFalse)
2668 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2669 cache_info->filename);
2670 return(cache_info->storage_class);
2671}
2672
2673/*
2674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675% %
2676% %
2677% %
cristyb32b90a2009-09-07 21:45:48 +00002678+ G e t P i x e l C a c h e T i l e S i z e %
2679% %
2680% %
2681% %
2682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2683%
2684% GetPixelCacheTileSize() returns the pixel cache tile size.
2685%
2686% The format of the GetPixelCacheTileSize() method is:
2687%
cristybb503372010-05-27 20:51:26 +00002688% void GetPixelCacheTileSize(const Image *image,size_t *width,
2689% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002690%
2691% A description of each parameter follows:
2692%
2693% o image: the image.
2694%
2695% o width: the optimize cache tile width in pixels.
2696%
2697% o height: the optimize cache tile height in pixels.
2698%
2699*/
cristya6577ff2011-09-02 19:54:26 +00002700MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002701 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002702{
cristy4c08aed2011-07-01 19:47:50 +00002703 CacheInfo
2704 *cache_info;
2705
cristyb32b90a2009-09-07 21:45:48 +00002706 assert(image != (Image *) NULL);
2707 assert(image->signature == MagickSignature);
2708 if (image->debug != MagickFalse)
2709 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002710 cache_info=(CacheInfo *) image->cache;
2711 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002712 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristy238287d2012-05-17 18:16:56 +00002713 if (GetImagePixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002714 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002715 *height=(*width);
2716}
2717
2718/*
2719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2720% %
2721% %
2722% %
cristy3ed852e2009-09-05 21:47:34 +00002723+ 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 %
2724% %
2725% %
2726% %
2727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2728%
2729% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2730% pixel cache. A virtual pixel is any pixel access that is outside the
2731% boundaries of the image cache.
2732%
2733% The format of the GetPixelCacheVirtualMethod() method is:
2734%
2735% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2736%
2737% A description of each parameter follows:
2738%
2739% o image: the image.
2740%
2741*/
cristyd1dd6e42011-09-04 01:46:08 +00002742MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002743{
2744 CacheInfo
2745 *cache_info;
2746
2747 assert(image != (Image *) NULL);
2748 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002749 assert(image->cache != (Cache) NULL);
2750 cache_info=(CacheInfo *) image->cache;
2751 assert(cache_info->signature == MagickSignature);
2752 return(cache_info->virtual_pixel_method);
2753}
2754
2755/*
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757% %
2758% %
2759% %
cristy4c08aed2011-07-01 19:47:50 +00002760+ 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 +00002761% %
2762% %
2763% %
2764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2765%
cristy4c08aed2011-07-01 19:47:50 +00002766% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2767% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002768%
cristy4c08aed2011-07-01 19:47:50 +00002769% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002770%
cristy4c08aed2011-07-01 19:47:50 +00002771% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002772%
2773% A description of each parameter follows:
2774%
2775% o image: the image.
2776%
2777*/
cristy4c08aed2011-07-01 19:47:50 +00002778static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002779{
2780 CacheInfo
2781 *cache_info;
2782
cristy5c9e6f22010-09-17 17:31:01 +00002783 const int
2784 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002785
cristy4c08aed2011-07-01 19:47:50 +00002786 const void
2787 *metacontent;
2788
cristye7cc7cf2010-09-21 13:26:47 +00002789 assert(image != (const Image *) NULL);
2790 assert(image->signature == MagickSignature);
2791 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002792 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002793 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002794 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002795 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2796 cache_info->nexus_info[id]);
2797 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002798}
2799
2800/*
2801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802% %
2803% %
2804% %
cristy4c08aed2011-07-01 19:47:50 +00002805+ 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 +00002806% %
2807% %
2808% %
2809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2810%
cristy4c08aed2011-07-01 19:47:50 +00002811% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2812% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002813%
cristy4c08aed2011-07-01 19:47:50 +00002814% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002815%
cristy4c08aed2011-07-01 19:47:50 +00002816% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002817% NexusInfo *nexus_info)
2818%
2819% A description of each parameter follows:
2820%
2821% o cache: the pixel cache.
2822%
cristy4c08aed2011-07-01 19:47:50 +00002823% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002824%
2825*/
cristya6577ff2011-09-02 19:54:26 +00002826MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002827 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002828{
2829 CacheInfo
2830 *cache_info;
2831
cristye7cc7cf2010-09-21 13:26:47 +00002832 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002833 cache_info=(CacheInfo *) cache;
2834 assert(cache_info->signature == MagickSignature);
2835 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002836 return((void *) NULL);
2837 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002838}
2839
2840/*
2841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2842% %
2843% %
2844% %
cristy4c08aed2011-07-01 19:47:50 +00002845% 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 +00002846% %
2847% %
2848% %
2849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2850%
cristy4c08aed2011-07-01 19:47:50 +00002851% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2852% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2853% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002854%
cristy4c08aed2011-07-01 19:47:50 +00002855% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002856%
cristy4c08aed2011-07-01 19:47:50 +00002857% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002858%
2859% A description of each parameter follows:
2860%
2861% o image: the image.
2862%
2863*/
cristy4c08aed2011-07-01 19:47:50 +00002864MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002865{
2866 CacheInfo
2867 *cache_info;
2868
cristy2036f5c2010-09-19 21:18:17 +00002869 const int
2870 id = GetOpenMPThreadId();
2871
cristy4c08aed2011-07-01 19:47:50 +00002872 const void
2873 *metacontent;
2874
cristy3ed852e2009-09-05 21:47:34 +00002875 assert(image != (const Image *) NULL);
2876 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002877 assert(image->cache != (Cache) NULL);
2878 cache_info=(CacheInfo *) image->cache;
2879 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002880 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002881 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002882 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002883 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002884 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2885 cache_info->nexus_info[id]);
2886 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002887}
2888
2889/*
2890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891% %
2892% %
2893% %
2894+ 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 %
2895% %
2896% %
2897% %
2898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2899%
2900% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2901% pixel cache as defined by the geometry parameters. A pointer to the pixels
2902% is returned if the pixels are transferred, otherwise a NULL is returned.
2903%
2904% The format of the GetVirtualPixelsFromNexus() method is:
2905%
cristy4c08aed2011-07-01 19:47:50 +00002906% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002907% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002908% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2909% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002910%
2911% A description of each parameter follows:
2912%
2913% o image: the image.
2914%
2915% o virtual_pixel_method: the virtual pixel method.
2916%
2917% o x,y,columns,rows: These values define the perimeter of a region of
2918% pixels.
2919%
2920% o nexus_info: the cache nexus to acquire.
2921%
2922% o exception: return any errors or warnings in this structure.
2923%
2924*/
2925
cristybb503372010-05-27 20:51:26 +00002926static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002927 DitherMatrix[64] =
2928 {
2929 0, 48, 12, 60, 3, 51, 15, 63,
2930 32, 16, 44, 28, 35, 19, 47, 31,
2931 8, 56, 4, 52, 11, 59, 7, 55,
2932 40, 24, 36, 20, 43, 27, 39, 23,
2933 2, 50, 14, 62, 1, 49, 13, 61,
2934 34, 18, 46, 30, 33, 17, 45, 29,
2935 10, 58, 6, 54, 9, 57, 5, 53,
2936 42, 26, 38, 22, 41, 25, 37, 21
2937 };
2938
cristybb503372010-05-27 20:51:26 +00002939static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002940{
cristybb503372010-05-27 20:51:26 +00002941 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002942 index;
2943
2944 index=x+DitherMatrix[x & 0x07]-32L;
2945 if (index < 0L)
2946 return(0L);
cristybb503372010-05-27 20:51:26 +00002947 if (index >= (ssize_t) columns)
2948 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002949 return(index);
2950}
2951
cristybb503372010-05-27 20:51:26 +00002952static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002953{
cristybb503372010-05-27 20:51:26 +00002954 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002955 index;
2956
2957 index=y+DitherMatrix[y & 0x07]-32L;
2958 if (index < 0L)
2959 return(0L);
cristybb503372010-05-27 20:51:26 +00002960 if (index >= (ssize_t) rows)
2961 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002962 return(index);
2963}
2964
cristybb503372010-05-27 20:51:26 +00002965static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002966{
2967 if (x < 0L)
2968 return(0L);
cristybb503372010-05-27 20:51:26 +00002969 if (x >= (ssize_t) columns)
2970 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002971 return(x);
2972}
2973
cristybb503372010-05-27 20:51:26 +00002974static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002975{
2976 if (y < 0L)
2977 return(0L);
cristybb503372010-05-27 20:51:26 +00002978 if (y >= (ssize_t) rows)
2979 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002980 return(y);
2981}
2982
cristybb503372010-05-27 20:51:26 +00002983static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002984{
cristybb503372010-05-27 20:51:26 +00002985 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002986}
2987
cristybb503372010-05-27 20:51:26 +00002988static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002989{
cristybb503372010-05-27 20:51:26 +00002990 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002991}
2992
cristybb503372010-05-27 20:51:26 +00002993static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2994 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002995{
2996 MagickModulo
2997 modulo;
2998
cristy6162bb42011-07-18 11:34:09 +00002999 /*
3000 Compute the remainder of dividing offset by extent. It returns not only
3001 the quotient (tile the offset falls in) but also the positive remainer
3002 within that tile such that 0 <= remainder < extent. This method is
3003 essentially a ldiv() using a floored modulo division rather than the
3004 normal default truncated modulo division.
3005 */
cristybb503372010-05-27 20:51:26 +00003006 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003007 if (offset < 0L)
3008 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003009 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003010 return(modulo);
3011}
3012
cristya6577ff2011-09-02 19:54:26 +00003013MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003014 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3015 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003016 ExceptionInfo *exception)
3017{
3018 CacheInfo
3019 *cache_info;
3020
3021 MagickOffsetType
3022 offset;
3023
3024 MagickSizeType
3025 length,
3026 number_pixels;
3027
3028 NexusInfo
3029 **virtual_nexus;
3030
cristy4c08aed2011-07-01 19:47:50 +00003031 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003032 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003033 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003034
3035 RectangleInfo
3036 region;
3037
cristy4c08aed2011-07-01 19:47:50 +00003038 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003039 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003040
cristy4c08aed2011-07-01 19:47:50 +00003041 register const void
3042 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003043
cristy4c08aed2011-07-01 19:47:50 +00003044 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003045 *restrict q;
3046
cristybb503372010-05-27 20:51:26 +00003047 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003048 i,
3049 u;
cristy3ed852e2009-09-05 21:47:34 +00003050
cristy4c08aed2011-07-01 19:47:50 +00003051 register unsigned char
3052 *restrict s;
3053
cristy105ba3c2011-07-18 02:28:38 +00003054 ssize_t
3055 v;
3056
cristy4c08aed2011-07-01 19:47:50 +00003057 void
cristy105ba3c2011-07-18 02:28:38 +00003058 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003059
cristy3ed852e2009-09-05 21:47:34 +00003060 /*
3061 Acquire pixels.
3062 */
cristye7cc7cf2010-09-21 13:26:47 +00003063 assert(image != (const Image *) NULL);
3064 assert(image->signature == MagickSignature);
3065 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003066 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003067 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003068 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003069 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003070 region.x=x;
3071 region.y=y;
3072 region.width=columns;
3073 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003074 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003075 if (pixels == (Quantum *) NULL)
3076 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003077 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003078 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3079 nexus_info->region.x;
3080 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3081 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003082 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3083 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003084 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3085 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003086 {
3087 MagickBooleanType
3088 status;
3089
3090 /*
3091 Pixel request is inside cache extents.
3092 */
cristy4c08aed2011-07-01 19:47:50 +00003093 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003094 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003095 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3096 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003097 return((const Quantum *) NULL);
3098 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003099 {
cristy4c08aed2011-07-01 19:47:50 +00003100 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003101 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003102 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003103 }
cristyacd2ed22011-08-30 01:44:23 +00003104 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003105 }
3106 /*
3107 Pixel request is outside cache extents.
3108 */
cristy4c08aed2011-07-01 19:47:50 +00003109 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003110 virtual_nexus=AcquirePixelCacheNexus(1);
3111 if (virtual_nexus == (NexusInfo **) NULL)
3112 {
cristy4c08aed2011-07-01 19:47:50 +00003113 if (virtual_nexus != (NexusInfo **) NULL)
3114 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003115 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003116 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003117 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003118 }
cristy105ba3c2011-07-18 02:28:38 +00003119 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3120 sizeof(*virtual_pixel));
3121 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003122 switch (virtual_pixel_method)
3123 {
cristy4c08aed2011-07-01 19:47:50 +00003124 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003125 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003126 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003127 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003128 case MaskVirtualPixelMethod:
3129 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003130 case EdgeVirtualPixelMethod:
3131 case CheckerTileVirtualPixelMethod:
3132 case HorizontalTileVirtualPixelMethod:
3133 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003134 {
cristy4c08aed2011-07-01 19:47:50 +00003135 if (cache_info->metacontent_extent != 0)
3136 {
cristy6162bb42011-07-18 11:34:09 +00003137 /*
3138 Acquire a metacontent buffer.
3139 */
cristya64b85d2011-09-14 01:02:31 +00003140 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003141 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003142 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003143 {
cristy4c08aed2011-07-01 19:47:50 +00003144 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3145 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003146 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003147 return((const Quantum *) NULL);
3148 }
cristy105ba3c2011-07-18 02:28:38 +00003149 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003150 cache_info->metacontent_extent);
3151 }
3152 switch (virtual_pixel_method)
3153 {
3154 case BlackVirtualPixelMethod:
3155 {
cristy30301712011-07-18 15:06:51 +00003156 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3157 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003158 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3159 break;
3160 }
3161 case GrayVirtualPixelMethod:
3162 {
cristy30301712011-07-18 15:06:51 +00003163 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003164 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3165 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003166 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3167 break;
3168 }
3169 case TransparentVirtualPixelMethod:
3170 {
cristy30301712011-07-18 15:06:51 +00003171 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3172 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003173 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3174 break;
3175 }
3176 case MaskVirtualPixelMethod:
3177 case WhiteVirtualPixelMethod:
3178 {
cristy30301712011-07-18 15:06:51 +00003179 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3180 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003181 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3182 break;
3183 }
3184 default:
3185 {
cristy9e0719b2011-12-29 03:45:45 +00003186 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3187 virtual_pixel);
3188 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3189 virtual_pixel);
3190 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3191 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003192 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3193 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003194 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3195 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003196 break;
3197 }
3198 }
cristy3ed852e2009-09-05 21:47:34 +00003199 break;
3200 }
3201 default:
cristy3ed852e2009-09-05 21:47:34 +00003202 break;
cristy3ed852e2009-09-05 21:47:34 +00003203 }
cristybb503372010-05-27 20:51:26 +00003204 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003205 {
cristybb503372010-05-27 20:51:26 +00003206 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003207 {
3208 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003209 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003210 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3211 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003212 {
3213 MagickModulo
3214 x_modulo,
3215 y_modulo;
3216
3217 /*
3218 Transfer a single pixel.
3219 */
3220 length=(MagickSizeType) 1;
3221 switch (virtual_pixel_method)
3222 {
cristy3ed852e2009-09-05 21:47:34 +00003223 default:
3224 {
3225 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003226 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003227 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003228 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003229 break;
3230 }
3231 case RandomVirtualPixelMethod:
3232 {
3233 if (cache_info->random_info == (RandomInfo *) NULL)
3234 cache_info->random_info=AcquireRandomInfo();
3235 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003236 RandomX(cache_info->random_info,cache_info->columns),
3237 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003238 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003239 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003240 break;
3241 }
3242 case DitherVirtualPixelMethod:
3243 {
3244 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003245 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003246 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003247 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003248 break;
3249 }
3250 case TileVirtualPixelMethod:
3251 {
3252 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3253 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3254 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003255 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003256 exception);
cristy4c08aed2011-07-01 19:47:50 +00003257 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003258 break;
3259 }
3260 case MirrorVirtualPixelMethod:
3261 {
3262 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3263 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003264 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003265 x_modulo.remainder-1L;
3266 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3267 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003268 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003269 y_modulo.remainder-1L;
3270 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003271 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003272 exception);
cristy4c08aed2011-07-01 19:47:50 +00003273 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003274 break;
3275 }
3276 case HorizontalTileEdgeVirtualPixelMethod:
3277 {
3278 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3279 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003280 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003281 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003282 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003283 break;
3284 }
3285 case VerticalTileEdgeVirtualPixelMethod:
3286 {
3287 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3288 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003289 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003290 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003291 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3292 break;
3293 }
3294 case BackgroundVirtualPixelMethod:
3295 case BlackVirtualPixelMethod:
3296 case GrayVirtualPixelMethod:
3297 case TransparentVirtualPixelMethod:
3298 case MaskVirtualPixelMethod:
3299 case WhiteVirtualPixelMethod:
3300 {
3301 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003302 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003303 break;
3304 }
3305 case EdgeVirtualPixelMethod:
3306 case CheckerTileVirtualPixelMethod:
3307 {
3308 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3309 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3310 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3311 {
3312 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003313 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003314 break;
3315 }
3316 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3317 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3318 exception);
3319 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3320 break;
3321 }
3322 case HorizontalTileVirtualPixelMethod:
3323 {
3324 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3325 {
3326 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003327 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003328 break;
3329 }
3330 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3331 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3332 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3333 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3334 exception);
3335 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3336 break;
3337 }
3338 case VerticalTileVirtualPixelMethod:
3339 {
3340 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3341 {
3342 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003343 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003344 break;
3345 }
3346 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3347 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3348 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3349 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3350 exception);
3351 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003352 break;
3353 }
3354 }
cristy4c08aed2011-07-01 19:47:50 +00003355 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003356 break;
cristyed231572011-07-14 02:18:59 +00003357 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003358 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003359 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003360 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003361 {
3362 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3363 s+=cache_info->metacontent_extent;
3364 }
cristy3ed852e2009-09-05 21:47:34 +00003365 continue;
3366 }
3367 /*
3368 Transfer a run of pixels.
3369 */
cristy4c08aed2011-07-01 19:47:50 +00003370 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3371 length,1UL,*virtual_nexus,exception);
3372 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003373 break;
cristy4c08aed2011-07-01 19:47:50 +00003374 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003375 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3376 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003377 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003378 {
cristy4c08aed2011-07-01 19:47:50 +00003379 (void) memcpy(s,r,(size_t) length);
3380 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003381 }
3382 }
3383 }
cristy4c08aed2011-07-01 19:47:50 +00003384 /*
3385 Free resources.
3386 */
cristy105ba3c2011-07-18 02:28:38 +00003387 if (virtual_metacontent != (void *) NULL)
3388 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003389 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3390 return(pixels);
3391}
3392
3393/*
3394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3395% %
3396% %
3397% %
3398+ G e t V i r t u a l P i x e l C a c h e %
3399% %
3400% %
3401% %
3402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3403%
3404% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3405% cache as defined by the geometry parameters. A pointer to the pixels
3406% is returned if the pixels are transferred, otherwise a NULL is returned.
3407%
3408% The format of the GetVirtualPixelCache() method is:
3409%
cristy4c08aed2011-07-01 19:47:50 +00003410% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003411% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3412% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003413% ExceptionInfo *exception)
3414%
3415% A description of each parameter follows:
3416%
3417% o image: the image.
3418%
3419% o virtual_pixel_method: the virtual pixel method.
3420%
3421% o x,y,columns,rows: These values define the perimeter of a region of
3422% pixels.
3423%
3424% o exception: return any errors or warnings in this structure.
3425%
3426*/
cristy4c08aed2011-07-01 19:47:50 +00003427static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003428 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3429 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003430{
3431 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003432 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003433
cristy5c9e6f22010-09-17 17:31:01 +00003434 const int
3435 id = GetOpenMPThreadId();
3436
cristy4c08aed2011-07-01 19:47:50 +00003437 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003438 *p;
cristy4c08aed2011-07-01 19:47:50 +00003439
cristye7cc7cf2010-09-21 13:26:47 +00003440 assert(image != (const Image *) NULL);
3441 assert(image->signature == MagickSignature);
3442 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003443 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003444 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003445 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003446 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003447 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003448 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003449}
3450
3451/*
3452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3453% %
3454% %
3455% %
3456% G e t V i r t u a l P i x e l Q u e u e %
3457% %
3458% %
3459% %
3460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3461%
cristy4c08aed2011-07-01 19:47:50 +00003462% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3463% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003464%
3465% The format of the GetVirtualPixelQueue() method is:
3466%
cristy4c08aed2011-07-01 19:47:50 +00003467% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003468%
3469% A description of each parameter follows:
3470%
3471% o image: the image.
3472%
3473*/
cristy4c08aed2011-07-01 19:47:50 +00003474MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003475{
3476 CacheInfo
3477 *cache_info;
3478
cristy2036f5c2010-09-19 21:18:17 +00003479 const int
3480 id = GetOpenMPThreadId();
3481
cristy3ed852e2009-09-05 21:47:34 +00003482 assert(image != (const Image *) NULL);
3483 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003484 assert(image->cache != (Cache) NULL);
3485 cache_info=(CacheInfo *) image->cache;
3486 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003487 if (cache_info->methods.get_virtual_pixels_handler !=
3488 (GetVirtualPixelsHandler) NULL)
3489 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003490 assert(id < (int) cache_info->number_threads);
3491 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003492}
3493
3494/*
3495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3496% %
3497% %
3498% %
3499% G e t V i r t u a l P i x e l s %
3500% %
3501% %
3502% %
3503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3504%
3505% GetVirtualPixels() returns an immutable pixel region. If the
3506% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003507% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003508% copy of the pixels or it may point to the original pixels in memory.
3509% Performance is maximized if the selected region is part of one row, or one
3510% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003511% (without a copy) if the image is in memory, or in a memory-mapped file. The
3512% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003513%
3514% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003515% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3516% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3517% access the meta-content (of type void) corresponding to the the
3518% region.
cristy3ed852e2009-09-05 21:47:34 +00003519%
3520% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3521%
3522% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3523% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3524% GetCacheViewAuthenticPixels() instead.
3525%
3526% The format of the GetVirtualPixels() method is:
3527%
cristy4c08aed2011-07-01 19:47:50 +00003528% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003529% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003530% ExceptionInfo *exception)
3531%
3532% A description of each parameter follows:
3533%
3534% o image: the image.
3535%
3536% o x,y,columns,rows: These values define the perimeter of a region of
3537% pixels.
3538%
3539% o exception: return any errors or warnings in this structure.
3540%
3541*/
cristy4c08aed2011-07-01 19:47:50 +00003542MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003543 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3544 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003545{
3546 CacheInfo
3547 *cache_info;
3548
cristy2036f5c2010-09-19 21:18:17 +00003549 const int
3550 id = GetOpenMPThreadId();
3551
cristy4c08aed2011-07-01 19:47:50 +00003552 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003553 *p;
cristy4c08aed2011-07-01 19:47:50 +00003554
cristy3ed852e2009-09-05 21:47:34 +00003555 assert(image != (const Image *) NULL);
3556 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003557 assert(image->cache != (Cache) NULL);
3558 cache_info=(CacheInfo *) image->cache;
3559 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003560 if (cache_info->methods.get_virtual_pixel_handler !=
3561 (GetVirtualPixelHandler) NULL)
3562 return(cache_info->methods.get_virtual_pixel_handler(image,
3563 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003564 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003565 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003566 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003567 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003568}
3569
3570/*
3571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3572% %
3573% %
3574% %
3575+ 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 %
3576% %
3577% %
3578% %
3579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3580%
cristy4c08aed2011-07-01 19:47:50 +00003581% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3582% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003583%
3584% The format of the GetVirtualPixelsCache() method is:
3585%
cristy4c08aed2011-07-01 19:47:50 +00003586% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003587%
3588% A description of each parameter follows:
3589%
3590% o image: the image.
3591%
3592*/
cristy4c08aed2011-07-01 19:47:50 +00003593static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003594{
3595 CacheInfo
3596 *cache_info;
3597
cristy5c9e6f22010-09-17 17:31:01 +00003598 const int
3599 id = GetOpenMPThreadId();
3600
cristye7cc7cf2010-09-21 13:26:47 +00003601 assert(image != (const Image *) NULL);
3602 assert(image->signature == MagickSignature);
3603 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003604 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003605 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003606 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003607 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003608}
3609
3610/*
3611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3612% %
3613% %
3614% %
3615+ G e t V i r t u a l P i x e l s N e x u s %
3616% %
3617% %
3618% %
3619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3620%
3621% GetVirtualPixelsNexus() returns the pixels associated with the specified
3622% cache nexus.
3623%
3624% The format of the GetVirtualPixelsNexus() method is:
3625%
cristy4c08aed2011-07-01 19:47:50 +00003626% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003627% NexusInfo *nexus_info)
3628%
3629% A description of each parameter follows:
3630%
3631% o cache: the pixel cache.
3632%
3633% o nexus_info: the cache nexus to return the colormap pixels.
3634%
3635*/
cristya6577ff2011-09-02 19:54:26 +00003636MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003637 NexusInfo *nexus_info)
3638{
3639 CacheInfo
3640 *cache_info;
3641
cristye7cc7cf2010-09-21 13:26:47 +00003642 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003643 cache_info=(CacheInfo *) cache;
3644 assert(cache_info->signature == MagickSignature);
3645 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003646 return((Quantum *) NULL);
3647 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003648}
3649
3650/*
3651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3652% %
3653% %
3654% %
cristy3ed852e2009-09-05 21:47:34 +00003655+ O p e n P i x e l C a c h e %
3656% %
3657% %
3658% %
3659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3660%
3661% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3662% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003663% metacontent, and memory mapping the cache if it is disk based. The cache
3664% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003665%
3666% The format of the OpenPixelCache() method is:
3667%
3668% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3669% ExceptionInfo *exception)
3670%
3671% A description of each parameter follows:
3672%
3673% o image: the image.
3674%
3675% o mode: ReadMode, WriteMode, or IOMode.
3676%
3677% o exception: return any errors or warnings in this structure.
3678%
3679*/
3680
cristyd43a46b2010-01-21 02:13:41 +00003681static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003682{
3683 cache_info->mapped=MagickFalse;
cristye42639a2012-08-23 01:53:24 +00003684 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3685 (size_t) cache_info->length));
cristy4c08aed2011-07-01 19:47:50 +00003686 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003687 {
3688 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003689 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003690 cache_info->length);
3691 }
3692}
3693
3694static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3695{
3696 CacheInfo
3697 *cache_info;
3698
3699 MagickOffsetType
cristy3ed852e2009-09-05 21:47:34 +00003700 extent,
3701 offset;
3702
3703 cache_info=(CacheInfo *) image->cache;
3704 if (image->debug != MagickFalse)
3705 {
3706 char
3707 format[MaxTextExtent],
3708 message[MaxTextExtent];
3709
cristyb9080c92009-12-01 20:13:26 +00003710 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003711 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003712 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003713 cache_info->cache_filename,cache_info->file,format);
3714 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3715 }
3716 if (length != (MagickSizeType) ((MagickOffsetType) length))
3717 return(MagickFalse);
cristy911f2b12012-10-18 14:55:28 +00003718 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3719 if (offset < 0)
cristy3ed852e2009-09-05 21:47:34 +00003720 return(MagickFalse);
cristy911f2b12012-10-18 14:55:28 +00003721 if ((MagickSizeType) offset >= length)
cristy3ed852e2009-09-05 21:47:34 +00003722 return(MagickTrue);
cristy911f2b12012-10-18 14:55:28 +00003723 extent=(MagickOffsetType) length-1;
cristy3b5a2cf2012-10-18 14:50:08 +00003724#if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3725 {
3726 MagickOffsetType
3727 count;
3728
cristy911f2b12012-10-18 14:55:28 +00003729 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
cristy3b5a2cf2012-10-18 14:50:08 +00003730 if (count != (MagickOffsetType) 1)
3731 return(MagickFalse);
3732 }
3733#else
3734 {
3735 int
3736 status;
3737
cristy911f2b12012-10-18 14:55:28 +00003738 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
cristy3b5a2cf2012-10-18 14:50:08 +00003739 if (status != 0)
3740 return(MagickFalse);
3741 }
3742#endif
3743 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003744}
3745
3746static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3747 ExceptionInfo *exception)
3748{
cristy3ed852e2009-09-05 21:47:34 +00003749 CacheInfo
3750 *cache_info,
3751 source_info;
3752
cristyf3a6a9d2010-11-07 21:02:56 +00003753 char
3754 format[MaxTextExtent],
3755 message[MaxTextExtent];
3756
cristy4c08aed2011-07-01 19:47:50 +00003757 MagickBooleanType
3758 status;
3759
cristy3ed852e2009-09-05 21:47:34 +00003760 MagickSizeType
3761 length,
3762 number_pixels;
3763
cristy3ed852e2009-09-05 21:47:34 +00003764 size_t
cristye076a6e2010-08-15 19:59:43 +00003765 columns,
cristy3ed852e2009-09-05 21:47:34 +00003766 packet_size;
3767
cristye7cc7cf2010-09-21 13:26:47 +00003768 assert(image != (const Image *) NULL);
3769 assert(image->signature == MagickSignature);
3770 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003771 if (image->debug != MagickFalse)
3772 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3773 if ((image->columns == 0) || (image->rows == 0))
3774 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3775 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003776 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003777 source_info=(*cache_info);
3778 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003779 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003780 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003781 cache_info->storage_class=image->storage_class;
3782 cache_info->colorspace=image->colorspace;
cristy8a46d822012-08-28 23:32:39 +00003783 cache_info->alpha_trait=image->alpha_trait;
cristy183a5c72012-01-30 01:40:35 +00003784 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003785 cache_info->rows=image->rows;
3786 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003787 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003788 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003789 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3790 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003791 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003792 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003793 if (image->ping != MagickFalse)
3794 {
cristy73724512010-04-12 14:43:14 +00003795 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003796 cache_info->pixels=(Quantum *) NULL;
3797 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003798 cache_info->length=0;
3799 return(MagickTrue);
3800 }
cristy3ed852e2009-09-05 21:47:34 +00003801 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003802 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003803 if (image->metacontent_extent != 0)
3804 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003805 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003806 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003807 if (cache_info->columns != columns)
3808 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3809 image->filename);
3810 cache_info->length=length;
3811 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003812 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003813 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003814 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3815 {
3816 status=AcquireMagickResource(MemoryResource,cache_info->length);
3817 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3818 (cache_info->type == MemoryCache))
3819 {
cristyd43a46b2010-01-21 02:13:41 +00003820 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003821 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003822 cache_info->pixels=source_info.pixels;
3823 else
3824 {
3825 /*
3826 Create memory pixel cache.
3827 */
cristy4c08aed2011-07-01 19:47:50 +00003828 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003829 if (image->debug != MagickFalse)
3830 {
cristy32cacff2011-12-31 03:36:27 +00003831 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003832 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003833 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3834 cache_info->filename,cache_info->mapped != MagickFalse ?
3835 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003836 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003837 format);
cristy3ed852e2009-09-05 21:47:34 +00003838 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3839 message);
3840 }
cristy3ed852e2009-09-05 21:47:34 +00003841 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003842 cache_info->metacontent=(void *) NULL;
3843 if (cache_info->metacontent_extent != 0)
3844 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003845 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003846 if ((source_info.storage_class != UndefinedClass) &&
3847 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003848 {
cristy4c08aed2011-07-01 19:47:50 +00003849 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003850 exception);
3851 RelinquishPixelCachePixels(&source_info);
3852 }
cristy4c08aed2011-07-01 19:47:50 +00003853 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003854 }
3855 }
3856 RelinquishMagickResource(MemoryResource,cache_info->length);
3857 }
3858 /*
3859 Create pixel cache on disk.
3860 */
3861 status=AcquireMagickResource(DiskResource,cache_info->length);
3862 if (status == MagickFalse)
3863 {
3864 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003865 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003866 return(MagickFalse);
3867 }
cristy413f1302012-01-01 17:48:27 +00003868 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3869 {
3870 (void) ClosePixelCacheOnDisk(cache_info);
3871 *cache_info->cache_filename='\0';
3872 }
cristy3ed852e2009-09-05 21:47:34 +00003873 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3874 {
3875 RelinquishMagickResource(DiskResource,cache_info->length);
3876 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3877 image->filename);
3878 return(MagickFalse);
3879 }
3880 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3881 cache_info->length);
3882 if (status == MagickFalse)
3883 {
3884 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3885 image->filename);
3886 return(MagickFalse);
3887 }
cristyed231572011-07-14 02:18:59 +00003888 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003889 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003890 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003891 cache_info->type=DiskCache;
3892 else
3893 {
3894 status=AcquireMagickResource(MapResource,cache_info->length);
3895 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3896 (cache_info->type != MemoryCache))
3897 cache_info->type=DiskCache;
3898 else
3899 {
cristy4c08aed2011-07-01 19:47:50 +00003900 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003901 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003902 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003903 {
cristy3ed852e2009-09-05 21:47:34 +00003904 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003905 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003906 }
3907 else
3908 {
3909 /*
3910 Create file-backed memory-mapped pixel cache.
3911 */
cristy4c08aed2011-07-01 19:47:50 +00003912 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003913 (void) ClosePixelCacheOnDisk(cache_info);
3914 cache_info->type=MapCache;
3915 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003916 cache_info->metacontent=(void *) NULL;
3917 if (cache_info->metacontent_extent != 0)
3918 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003919 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003920 if ((source_info.storage_class != UndefinedClass) &&
3921 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003922 {
3923 status=ClonePixelCachePixels(cache_info,&source_info,
3924 exception);
3925 RelinquishPixelCachePixels(&source_info);
3926 }
3927 if (image->debug != MagickFalse)
3928 {
cristy413f1302012-01-01 17:48:27 +00003929 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003930 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003931 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003932 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003933 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003934 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003935 format);
cristy3ed852e2009-09-05 21:47:34 +00003936 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3937 message);
3938 }
cristy4c08aed2011-07-01 19:47:50 +00003939 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003940 }
3941 }
3942 RelinquishMagickResource(MapResource,cache_info->length);
3943 }
cristy4c08aed2011-07-01 19:47:50 +00003944 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003945 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003946 {
3947 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3948 RelinquishPixelCachePixels(&source_info);
3949 }
3950 if (image->debug != MagickFalse)
3951 {
cristyb9080c92009-12-01 20:13:26 +00003952 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003953 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003954 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003955 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003956 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003957 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003958 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3959 }
cristy4c08aed2011-07-01 19:47:50 +00003960 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003961}
3962
3963/*
3964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3965% %
3966% %
3967% %
3968+ P e r s i s t P i x e l C a c h e %
3969% %
3970% %
3971% %
3972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3973%
3974% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3975% persistent pixel cache is one that resides on disk and is not destroyed
3976% when the program exits.
3977%
3978% The format of the PersistPixelCache() method is:
3979%
3980% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3981% const MagickBooleanType attach,MagickOffsetType *offset,
3982% ExceptionInfo *exception)
3983%
3984% A description of each parameter follows:
3985%
3986% o image: the image.
3987%
3988% o filename: the persistent pixel cache filename.
3989%
cristyf3a6a9d2010-11-07 21:02:56 +00003990% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003991%
cristy3ed852e2009-09-05 21:47:34 +00003992% o initialize: A value other than zero initializes the persistent pixel
3993% cache.
3994%
3995% o offset: the offset in the persistent cache to store pixels.
3996%
3997% o exception: return any errors or warnings in this structure.
3998%
3999*/
4000MagickExport MagickBooleanType PersistPixelCache(Image *image,
4001 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4002 ExceptionInfo *exception)
4003{
4004 CacheInfo
4005 *cache_info,
4006 *clone_info;
4007
4008 Image
4009 clone_image;
4010
cristy3ed852e2009-09-05 21:47:34 +00004011 MagickBooleanType
4012 status;
4013
cristye076a6e2010-08-15 19:59:43 +00004014 ssize_t
4015 page_size;
4016
cristy3ed852e2009-09-05 21:47:34 +00004017 assert(image != (Image *) NULL);
4018 assert(image->signature == MagickSignature);
4019 if (image->debug != MagickFalse)
4020 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4021 assert(image->cache != (void *) NULL);
4022 assert(filename != (const char *) NULL);
4023 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004024 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004025 cache_info=(CacheInfo *) image->cache;
4026 assert(cache_info->signature == MagickSignature);
4027 if (attach != MagickFalse)
4028 {
4029 /*
cristy01b7eb02009-09-10 23:10:14 +00004030 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004031 */
4032 if (image->debug != MagickFalse)
4033 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004034 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004035 (void) CopyMagickString(cache_info->cache_filename,filename,
4036 MaxTextExtent);
4037 cache_info->type=DiskCache;
4038 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004039 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004040 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004041 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004042 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004043 }
cristy01b7eb02009-09-10 23:10:14 +00004044 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4045 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004046 {
cristyf84a1932010-01-03 18:00:18 +00004047 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004048 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004049 (cache_info->reference_count == 1))
4050 {
4051 int
4052 status;
4053
4054 /*
cristy01b7eb02009-09-10 23:10:14 +00004055 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004056 */
cristy320684d2011-09-23 14:55:47 +00004057 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004058 if (status == 0)
4059 {
4060 (void) CopyMagickString(cache_info->cache_filename,filename,
4061 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004062 *offset+=cache_info->length+page_size-(cache_info->length %
4063 page_size);
cristyf84a1932010-01-03 18:00:18 +00004064 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004065 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004066 if (image->debug != MagickFalse)
4067 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4068 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004069 return(MagickTrue);
4070 }
4071 }
cristyf84a1932010-01-03 18:00:18 +00004072 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004073 }
4074 /*
cristy01b7eb02009-09-10 23:10:14 +00004075 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004076 */
4077 clone_image=(*image);
4078 clone_info=(CacheInfo *) clone_image.cache;
4079 image->cache=ClonePixelCache(cache_info);
4080 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4081 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4082 cache_info->type=DiskCache;
4083 cache_info->offset=(*offset);
4084 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004085 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004086 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004087 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004088 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004089 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4090 return(status);
4091}
4092
4093/*
4094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4095% %
4096% %
4097% %
cristyc11dace2012-01-24 16:39:46 +00004098+ 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 +00004099% %
4100% %
4101% %
4102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4103%
cristyc11dace2012-01-24 16:39:46 +00004104% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4105% defined by the region rectangle and returns a pointer to the region. This
4106% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004107% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4108% pixels are transferred, otherwise a NULL is returned.
4109%
cristyc11dace2012-01-24 16:39:46 +00004110% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004111%
cristyc11dace2012-01-24 16:39:46 +00004112% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004113% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004114% const MagickBooleanType clone,NexusInfo *nexus_info,
4115% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004116%
4117% A description of each parameter follows:
4118%
4119% o image: the image.
4120%
4121% o x,y,columns,rows: These values define the perimeter of a region of
4122% pixels.
4123%
4124% o nexus_info: the cache nexus to set.
4125%
cristy65dbf172011-10-06 17:32:04 +00004126% o clone: clone the pixel cache.
4127%
cristy3ed852e2009-09-05 21:47:34 +00004128% o exception: return any errors or warnings in this structure.
4129%
4130*/
cristyc11dace2012-01-24 16:39:46 +00004131MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4132 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004133 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004134{
4135 CacheInfo
4136 *cache_info;
4137
4138 MagickOffsetType
4139 offset;
4140
4141 MagickSizeType
4142 number_pixels;
4143
4144 RectangleInfo
4145 region;
4146
4147 /*
4148 Validate pixel cache geometry.
4149 */
cristye7cc7cf2010-09-21 13:26:47 +00004150 assert(image != (const Image *) NULL);
4151 assert(image->signature == MagickSignature);
4152 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004153 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004154 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004155 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004156 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004157 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4158 {
4159 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004160 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004161 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004162 }
cristybb503372010-05-27 20:51:26 +00004163 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4164 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004165 {
4166 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004167 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004168 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004169 }
4170 offset=(MagickOffsetType) y*cache_info->columns+x;
4171 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004172 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004173 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4174 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4175 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004176 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004177 /*
4178 Return pixel cache.
4179 */
4180 region.x=x;
4181 region.y=y;
4182 region.width=columns;
4183 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004184 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004185}
4186
4187/*
4188%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4189% %
4190% %
4191% %
4192+ 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 %
4193% %
4194% %
4195% %
4196%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4197%
4198% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4199% defined by the region rectangle and returns a pointer to the region. This
4200% region is subsequently transferred from the pixel cache with
4201% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4202% pixels are transferred, otherwise a NULL is returned.
4203%
4204% The format of the QueueAuthenticPixelsCache() method is:
4205%
cristy4c08aed2011-07-01 19:47:50 +00004206% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004207% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004208% ExceptionInfo *exception)
4209%
4210% A description of each parameter follows:
4211%
4212% o image: the image.
4213%
4214% o x,y,columns,rows: These values define the perimeter of a region of
4215% pixels.
4216%
4217% o exception: return any errors or warnings in this structure.
4218%
4219*/
cristy4c08aed2011-07-01 19:47:50 +00004220static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004221 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004222 ExceptionInfo *exception)
4223{
4224 CacheInfo
4225 *cache_info;
4226
cristy5c9e6f22010-09-17 17:31:01 +00004227 const int
4228 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004229
cristy4c08aed2011-07-01 19:47:50 +00004230 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004231 *q;
cristy4c08aed2011-07-01 19:47:50 +00004232
cristye7cc7cf2010-09-21 13:26:47 +00004233 assert(image != (const Image *) NULL);
4234 assert(image->signature == MagickSignature);
4235 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004236 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004237 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004238 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004239 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004240 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004241 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004242}
4243
4244/*
4245%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4246% %
4247% %
4248% %
4249% Q u e u e A u t h e n t i c P i x e l s %
4250% %
4251% %
4252% %
4253%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4254%
4255% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004256% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004257% region is returned, otherwise NULL is returned. The returned pointer may
4258% point to a temporary working buffer for the pixels or it may point to the
4259% final location of the pixels in memory.
4260%
4261% Write-only access means that any existing pixel values corresponding to
4262% the region are ignored. This is useful if the initial image is being
4263% created from scratch, or if the existing pixel values are to be
4264% completely replaced without need to refer to their pre-existing values.
4265% The application is free to read and write the pixel buffer returned by
4266% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4267% initialize the pixel array values. Initializing pixel array values is the
4268% application's responsibility.
4269%
4270% Performance is maximized if the selected region is part of one row, or
4271% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004272% pixels in-place (without a copy) if the image is in memory, or in a
4273% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004274% by the user.
4275%
4276% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004277% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4278% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4279% obtain the meta-content (of type void) corresponding to the region.
4280% Once the Quantum (and/or Quantum) array has been updated, the
4281% changes must be saved back to the underlying image using
4282% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004283%
4284% The format of the QueueAuthenticPixels() method is:
4285%
cristy4c08aed2011-07-01 19:47:50 +00004286% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004287% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004288% ExceptionInfo *exception)
4289%
4290% A description of each parameter follows:
4291%
4292% o image: the image.
4293%
4294% o x,y,columns,rows: These values define the perimeter of a region of
4295% pixels.
4296%
4297% o exception: return any errors or warnings in this structure.
4298%
4299*/
cristy4c08aed2011-07-01 19:47:50 +00004300MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004301 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004302 ExceptionInfo *exception)
4303{
4304 CacheInfo
4305 *cache_info;
4306
cristy2036f5c2010-09-19 21:18:17 +00004307 const int
4308 id = GetOpenMPThreadId();
4309
cristy4c08aed2011-07-01 19:47:50 +00004310 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004311 *q;
cristy4c08aed2011-07-01 19:47:50 +00004312
cristy3ed852e2009-09-05 21:47:34 +00004313 assert(image != (Image *) NULL);
4314 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004315 assert(image->cache != (Cache) NULL);
4316 cache_info=(CacheInfo *) image->cache;
4317 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004318 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004319 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004320 {
cristyc36c8822012-02-14 14:02:36 +00004321 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4322 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004323 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004324 }
cristy2036f5c2010-09-19 21:18:17 +00004325 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004326 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004327 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004328 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004329}
4330
4331/*
4332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4333% %
4334% %
4335% %
cristy4c08aed2011-07-01 19:47:50 +00004336+ 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 +00004337% %
4338% %
4339% %
4340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4341%
cristy4c08aed2011-07-01 19:47:50 +00004342% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004343% the pixel cache.
4344%
cristy4c08aed2011-07-01 19:47:50 +00004345% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004346%
cristy4c08aed2011-07-01 19:47:50 +00004347% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004348% NexusInfo *nexus_info,ExceptionInfo *exception)
4349%
4350% A description of each parameter follows:
4351%
4352% o cache_info: the pixel cache.
4353%
cristy4c08aed2011-07-01 19:47:50 +00004354% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004355%
4356% o exception: return any errors or warnings in this structure.
4357%
4358*/
cristy4c08aed2011-07-01 19:47:50 +00004359static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004360 NexusInfo *nexus_info,ExceptionInfo *exception)
4361{
4362 MagickOffsetType
4363 count,
4364 offset;
4365
4366 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004367 extent,
4368 length;
cristy3ed852e2009-09-05 21:47:34 +00004369
cristybb503372010-05-27 20:51:26 +00004370 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004371 y;
4372
cristy4c08aed2011-07-01 19:47:50 +00004373 register unsigned char
4374 *restrict q;
4375
cristybb503372010-05-27 20:51:26 +00004376 size_t
cristy3ed852e2009-09-05 21:47:34 +00004377 rows;
4378
cristy4c08aed2011-07-01 19:47:50 +00004379 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004380 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004381 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004382 return(MagickTrue);
4383 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4384 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004385 length=(MagickSizeType) nexus_info->region.width*
4386 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004387 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004388 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004389 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004390 switch (cache_info->type)
4391 {
4392 case MemoryCache:
4393 case MapCache:
4394 {
cristy4c08aed2011-07-01 19:47:50 +00004395 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004396 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004397
4398 /*
cristy4c08aed2011-07-01 19:47:50 +00004399 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004400 */
cristydd341db2010-03-04 19:06:38 +00004401 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004402 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004403 {
cristy48078b12010-09-23 17:11:01 +00004404 length=extent;
cristydd341db2010-03-04 19:06:38 +00004405 rows=1UL;
4406 }
cristy4c08aed2011-07-01 19:47:50 +00004407 p=(unsigned char *) cache_info->metacontent+offset*
4408 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004409 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004410 {
cristy8f036fe2010-09-18 02:02:00 +00004411 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004412 p+=cache_info->metacontent_extent*cache_info->columns;
4413 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004414 }
4415 break;
4416 }
4417 case DiskCache:
4418 {
4419 /*
cristy4c08aed2011-07-01 19:47:50 +00004420 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004421 */
4422 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4423 {
4424 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4425 cache_info->cache_filename);
4426 return(MagickFalse);
4427 }
cristydd341db2010-03-04 19:06:38 +00004428 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004429 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004430 {
cristy48078b12010-09-23 17:11:01 +00004431 length=extent;
cristydd341db2010-03-04 19:06:38 +00004432 rows=1UL;
4433 }
cristy48078b12010-09-23 17:11:01 +00004434 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004435 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004436 {
cristy48078b12010-09-23 17:11:01 +00004437 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004438 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004439 cache_info->metacontent_extent,length,(unsigned char *) q);
4440 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004441 break;
4442 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004443 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004444 }
cristyc11dace2012-01-24 16:39:46 +00004445 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4446 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004447 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004448 {
4449 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4450 cache_info->cache_filename);
4451 return(MagickFalse);
4452 }
4453 break;
4454 }
4455 default:
4456 break;
4457 }
4458 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004459 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004460 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004461 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004462 nexus_info->region.width,(double) nexus_info->region.height,(double)
4463 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004464 return(MagickTrue);
4465}
4466
4467/*
4468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4469% %
4470% %
4471% %
4472+ R e a d P i x e l C a c h e P i x e l s %
4473% %
4474% %
4475% %
4476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4477%
4478% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4479% cache.
4480%
4481% The format of the ReadPixelCachePixels() method is:
4482%
4483% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4484% NexusInfo *nexus_info,ExceptionInfo *exception)
4485%
4486% A description of each parameter follows:
4487%
4488% o cache_info: the pixel cache.
4489%
4490% o nexus_info: the cache nexus to read the pixels.
4491%
4492% o exception: return any errors or warnings in this structure.
4493%
4494*/
4495static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4496 NexusInfo *nexus_info,ExceptionInfo *exception)
4497{
4498 MagickOffsetType
4499 count,
4500 offset;
4501
4502 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004503 extent,
4504 length;
cristy3ed852e2009-09-05 21:47:34 +00004505
cristy4c08aed2011-07-01 19:47:50 +00004506 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004507 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004508
cristye076a6e2010-08-15 19:59:43 +00004509 register ssize_t
4510 y;
4511
cristybb503372010-05-27 20:51:26 +00004512 size_t
cristy3ed852e2009-09-05 21:47:34 +00004513 rows;
4514
cristy4c08aed2011-07-01 19:47:50 +00004515 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004516 return(MagickTrue);
4517 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4518 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004519 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004520 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004521 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004522 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004523 q=nexus_info->pixels;
4524 switch (cache_info->type)
4525 {
4526 case MemoryCache:
4527 case MapCache:
4528 {
cristy4c08aed2011-07-01 19:47:50 +00004529 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004530 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004531
4532 /*
4533 Read pixels from memory.
4534 */
cristydd341db2010-03-04 19:06:38 +00004535 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004536 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004537 {
cristy48078b12010-09-23 17:11:01 +00004538 length=extent;
cristydd341db2010-03-04 19:06:38 +00004539 rows=1UL;
4540 }
cristyed231572011-07-14 02:18:59 +00004541 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004542 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004543 {
cristy8f036fe2010-09-18 02:02:00 +00004544 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004545 p+=cache_info->number_channels*cache_info->columns;
4546 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004547 }
4548 break;
4549 }
4550 case DiskCache:
4551 {
4552 /*
4553 Read pixels from disk.
4554 */
4555 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4556 {
4557 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4558 cache_info->cache_filename);
4559 return(MagickFalse);
4560 }
cristydd341db2010-03-04 19:06:38 +00004561 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004562 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004563 {
cristy48078b12010-09-23 17:11:01 +00004564 length=extent;
cristydd341db2010-03-04 19:06:38 +00004565 rows=1UL;
4566 }
cristybb503372010-05-27 20:51:26 +00004567 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004568 {
4569 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004570 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004571 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004572 break;
4573 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004574 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004575 }
cristyc11dace2012-01-24 16:39:46 +00004576 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4577 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004578 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004579 {
4580 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4581 cache_info->cache_filename);
4582 return(MagickFalse);
4583 }
4584 break;
4585 }
4586 default:
4587 break;
4588 }
4589 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004590 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004591 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004592 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004593 nexus_info->region.width,(double) nexus_info->region.height,(double)
4594 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004595 return(MagickTrue);
4596}
4597
4598/*
4599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4600% %
4601% %
4602% %
4603+ R e f e r e n c e P i x e l C a c h e %
4604% %
4605% %
4606% %
4607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4608%
4609% ReferencePixelCache() increments the reference count associated with the
4610% pixel cache returning a pointer to the cache.
4611%
4612% The format of the ReferencePixelCache method is:
4613%
4614% Cache ReferencePixelCache(Cache cache_info)
4615%
4616% A description of each parameter follows:
4617%
4618% o cache_info: the pixel cache.
4619%
4620*/
cristya6577ff2011-09-02 19:54:26 +00004621MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004622{
4623 CacheInfo
4624 *cache_info;
4625
4626 assert(cache != (Cache *) NULL);
4627 cache_info=(CacheInfo *) cache;
4628 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004629 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004630 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004631 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004632 return(cache_info);
4633}
4634
4635/*
4636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4637% %
4638% %
4639% %
4640+ S e t P i x e l C a c h e M e t h o d s %
4641% %
4642% %
4643% %
4644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4645%
4646% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4647%
4648% The format of the SetPixelCacheMethods() method is:
4649%
4650% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4651%
4652% A description of each parameter follows:
4653%
4654% o cache: the pixel cache.
4655%
4656% o cache_methods: Specifies a pointer to a CacheMethods structure.
4657%
4658*/
cristya6577ff2011-09-02 19:54:26 +00004659MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004660{
4661 CacheInfo
4662 *cache_info;
4663
4664 GetOneAuthenticPixelFromHandler
4665 get_one_authentic_pixel_from_handler;
4666
4667 GetOneVirtualPixelFromHandler
4668 get_one_virtual_pixel_from_handler;
4669
4670 /*
4671 Set cache pixel methods.
4672 */
4673 assert(cache != (Cache) NULL);
4674 assert(cache_methods != (CacheMethods *) NULL);
4675 cache_info=(CacheInfo *) cache;
4676 assert(cache_info->signature == MagickSignature);
4677 if (cache_info->debug != MagickFalse)
4678 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4679 cache_info->filename);
4680 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4681 cache_info->methods.get_virtual_pixel_handler=
4682 cache_methods->get_virtual_pixel_handler;
4683 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4684 cache_info->methods.destroy_pixel_handler=
4685 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004686 if (cache_methods->get_virtual_metacontent_from_handler !=
4687 (GetVirtualMetacontentFromHandler) NULL)
4688 cache_info->methods.get_virtual_metacontent_from_handler=
4689 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004690 if (cache_methods->get_authentic_pixels_handler !=
4691 (GetAuthenticPixelsHandler) NULL)
4692 cache_info->methods.get_authentic_pixels_handler=
4693 cache_methods->get_authentic_pixels_handler;
4694 if (cache_methods->queue_authentic_pixels_handler !=
4695 (QueueAuthenticPixelsHandler) NULL)
4696 cache_info->methods.queue_authentic_pixels_handler=
4697 cache_methods->queue_authentic_pixels_handler;
4698 if (cache_methods->sync_authentic_pixels_handler !=
4699 (SyncAuthenticPixelsHandler) NULL)
4700 cache_info->methods.sync_authentic_pixels_handler=
4701 cache_methods->sync_authentic_pixels_handler;
4702 if (cache_methods->get_authentic_pixels_from_handler !=
4703 (GetAuthenticPixelsFromHandler) NULL)
4704 cache_info->methods.get_authentic_pixels_from_handler=
4705 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004706 if (cache_methods->get_authentic_metacontent_from_handler !=
4707 (GetAuthenticMetacontentFromHandler) NULL)
4708 cache_info->methods.get_authentic_metacontent_from_handler=
4709 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004710 get_one_virtual_pixel_from_handler=
4711 cache_info->methods.get_one_virtual_pixel_from_handler;
4712 if (get_one_virtual_pixel_from_handler !=
4713 (GetOneVirtualPixelFromHandler) NULL)
4714 cache_info->methods.get_one_virtual_pixel_from_handler=
4715 cache_methods->get_one_virtual_pixel_from_handler;
4716 get_one_authentic_pixel_from_handler=
4717 cache_methods->get_one_authentic_pixel_from_handler;
4718 if (get_one_authentic_pixel_from_handler !=
4719 (GetOneAuthenticPixelFromHandler) NULL)
4720 cache_info->methods.get_one_authentic_pixel_from_handler=
4721 cache_methods->get_one_authentic_pixel_from_handler;
4722}
4723
4724/*
4725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4726% %
4727% %
4728% %
4729+ S e t P i x e l C a c h e N e x u s P i x e l s %
4730% %
4731% %
4732% %
4733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4734%
4735% SetPixelCacheNexusPixels() defines the region of the cache for the
4736% specified cache nexus.
4737%
4738% The format of the SetPixelCacheNexusPixels() method is:
4739%
cristy265a2b22012-05-11 12:48:50 +00004740% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004741% const RectangleInfo *region,NexusInfo *nexus_info,
4742% ExceptionInfo *exception)
4743%
4744% A description of each parameter follows:
4745%
4746% o image: the image.
4747%
cristy265a2b22012-05-11 12:48:50 +00004748% o mode: ReadMode, WriteMode, or IOMode.
4749%
cristy3ed852e2009-09-05 21:47:34 +00004750% o region: A pointer to the RectangleInfo structure that defines the
4751% region of this particular cache nexus.
4752%
4753% o nexus_info: the cache nexus to set.
4754%
4755% o exception: return any errors or warnings in this structure.
4756%
4757*/
cristyabd6e372010-09-15 19:11:26 +00004758
cristyf1832792012-05-08 18:38:18 +00004759static inline MagickBooleanType AcquireCacheNexusPixels(
4760 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4761 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004762{
4763 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4764 return(MagickFalse);
4765 nexus_info->mapped=MagickFalse;
cristye42639a2012-08-23 01:53:24 +00004766 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4767 (size_t) nexus_info->length));
cristy4c08aed2011-07-01 19:47:50 +00004768 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004769 {
4770 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004771 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004772 nexus_info->length);
4773 }
cristy4c08aed2011-07-01 19:47:50 +00004774 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004775 {
4776 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004777 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004778 cache_info->filename);
4779 return(MagickFalse);
4780 }
4781 return(MagickTrue);
4782}
4783
cristyadf82722012-05-11 17:34:16 +00004784static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4785 const MapMode mode)
4786{
cristyfc5845e2012-05-11 18:18:13 +00004787 if (mode == ReadMode)
4788 {
4789 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4790 return;
4791 }
4792 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004793}
4794
cristy265a2b22012-05-11 12:48:50 +00004795static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004796 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4797{
4798 CacheInfo
4799 *cache_info;
4800
4801 MagickBooleanType
4802 status;
4803
cristy3ed852e2009-09-05 21:47:34 +00004804 MagickSizeType
4805 length,
4806 number_pixels;
4807
cristy3ed852e2009-09-05 21:47:34 +00004808 cache_info=(CacheInfo *) image->cache;
4809 assert(cache_info->signature == MagickSignature);
4810 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004811 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004812 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004813 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004814 {
cristybb503372010-05-27 20:51:26 +00004815 ssize_t
cristybad067a2010-02-15 17:20:55 +00004816 x,
4817 y;
cristy3ed852e2009-09-05 21:47:34 +00004818
cristyeaedf062010-05-29 22:36:02 +00004819 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4820 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004821 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4822 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004823 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004824 ((nexus_info->region.width == cache_info->columns) ||
4825 ((nexus_info->region.width % cache_info->columns) == 0)))))
4826 {
4827 MagickOffsetType
4828 offset;
4829
4830 /*
4831 Pixels are accessed directly from memory.
4832 */
4833 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4834 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004835 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004836 offset;
4837 nexus_info->metacontent=(void *) NULL;
4838 if (cache_info->metacontent_extent != 0)
4839 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4840 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004841 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004842 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004843 }
4844 }
4845 /*
4846 Pixels are stored in a cache region until they are synced to the cache.
4847 */
4848 number_pixels=(MagickSizeType) nexus_info->region.width*
4849 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004850 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004851 if (cache_info->metacontent_extent != 0)
4852 length+=number_pixels*cache_info->metacontent_extent;
4853 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004854 {
4855 nexus_info->length=length;
4856 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4857 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004858 {
4859 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004860 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004861 }
cristy3ed852e2009-09-05 21:47:34 +00004862 }
4863 else
4864 if (nexus_info->length != length)
4865 {
4866 RelinquishCacheNexusPixels(nexus_info);
4867 nexus_info->length=length;
4868 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4869 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004870 {
4871 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004872 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004873 }
cristy3ed852e2009-09-05 21:47:34 +00004874 }
4875 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004876 nexus_info->metacontent=(void *) NULL;
4877 if (cache_info->metacontent_extent != 0)
4878 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004879 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004880 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004881 return(nexus_info->pixels);
4882}
4883
4884/*
4885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4886% %
4887% %
4888% %
4889% 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 %
4890% %
4891% %
4892% %
4893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4894%
4895% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4896% pixel cache and returns the previous setting. A virtual pixel is any pixel
4897% access that is outside the boundaries of the image cache.
4898%
4899% The format of the SetPixelCacheVirtualMethod() method is:
4900%
cristy387430f2012-02-07 13:09:46 +00004901% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4902% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004903%
4904% A description of each parameter follows:
4905%
4906% o image: the image.
4907%
4908% o virtual_pixel_method: choose the type of virtual pixel.
4909%
cristy387430f2012-02-07 13:09:46 +00004910% o exception: return any errors or warnings in this structure.
4911%
cristy3ed852e2009-09-05 21:47:34 +00004912*/
cristy3d4cb882012-02-07 19:11:26 +00004913
4914static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4915 ExceptionInfo *exception)
4916{
4917 CacheInfo
4918 *cache_info;
4919
cristyf2719112012-05-06 18:38:46 +00004920 CacheView
4921 *image_view;
4922
cristy3d4cb882012-02-07 19:11:26 +00004923 MagickBooleanType
4924 status;
4925
4926 ssize_t
4927 y;
4928
4929 assert(image != (Image *) NULL);
4930 assert(image->signature == MagickSignature);
4931 if (image->debug != MagickFalse)
4932 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4933 assert(image->cache != (Cache) NULL);
4934 cache_info=(CacheInfo *) image->cache;
4935 assert(cache_info->signature == MagickSignature);
cristy8a46d822012-08-28 23:32:39 +00004936 image->alpha_trait=BlendPixelTrait;
cristy3d4cb882012-02-07 19:11:26 +00004937 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004938 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004939#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +00004940 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00004941 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004942#endif
4943 for (y=0; y < (ssize_t) image->rows; y++)
4944 {
cristy3d4cb882012-02-07 19:11:26 +00004945 register Quantum
4946 *restrict q;
4947
4948 register ssize_t
4949 x;
4950
4951 if (status == MagickFalse)
4952 continue;
cristy23d198a2012-03-13 13:48:08 +00004953 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004954 if (q == (Quantum *) NULL)
4955 {
4956 status=MagickFalse;
4957 continue;
4958 }
4959 for (x=0; x < (ssize_t) image->columns; x++)
4960 {
4961 SetPixelAlpha(image,alpha,q);
4962 q+=GetPixelChannels(image);
4963 }
cristy23d198a2012-03-13 13:48:08 +00004964 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004965 }
cristy23d198a2012-03-13 13:48:08 +00004966 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004967 return(status);
4968}
4969
cristy387430f2012-02-07 13:09:46 +00004970MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4971 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004972{
4973 CacheInfo
4974 *cache_info;
4975
4976 VirtualPixelMethod
4977 method;
4978
4979 assert(image != (Image *) NULL);
4980 assert(image->signature == MagickSignature);
4981 if (image->debug != MagickFalse)
4982 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4983 assert(image->cache != (Cache) NULL);
4984 cache_info=(CacheInfo *) image->cache;
4985 assert(cache_info->signature == MagickSignature);
4986 method=cache_info->virtual_pixel_method;
4987 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy13c10082012-05-29 11:22:12 +00004988 if ((image->columns != 0) && (image->rows != 0))
4989 switch (virtual_pixel_method)
cristy387430f2012-02-07 13:09:46 +00004990 {
cristy13c10082012-05-29 11:22:12 +00004991 case BackgroundVirtualPixelMethod:
4992 {
cristy8a46d822012-08-28 23:32:39 +00004993 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4994 (image->alpha_trait != BlendPixelTrait))
cristy13c10082012-05-29 11:22:12 +00004995 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy6386b792012-06-23 17:44:57 +00004996 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4997 (IsGrayColorspace(image->colorspace) != MagickFalse))
cristyb09db112012-07-11 12:04:31 +00004998 (void) TransformImageColorspace(image,RGBColorspace,exception);
cristy13c10082012-05-29 11:22:12 +00004999 break;
5000 }
5001 case TransparentVirtualPixelMethod:
5002 {
cristy8a46d822012-08-28 23:32:39 +00005003 if (image->alpha_trait != BlendPixelTrait)
cristy13c10082012-05-29 11:22:12 +00005004 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5005 break;
5006 }
5007 default:
5008 break;
cristy387430f2012-02-07 13:09:46 +00005009 }
cristy3ed852e2009-09-05 21:47:34 +00005010 return(method);
5011}
5012
5013/*
5014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5015% %
5016% %
5017% %
5018+ 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 %
5019% %
5020% %
5021% %
5022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5023%
5024% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5025% in-memory or disk cache. The method returns MagickTrue if the pixel region
5026% is synced, otherwise MagickFalse.
5027%
5028% The format of the SyncAuthenticPixelCacheNexus() method is:
5029%
5030% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5031% NexusInfo *nexus_info,ExceptionInfo *exception)
5032%
5033% A description of each parameter follows:
5034%
5035% o image: the image.
5036%
5037% o nexus_info: the cache nexus to sync.
5038%
5039% o exception: return any errors or warnings in this structure.
5040%
5041*/
cristya6577ff2011-09-02 19:54:26 +00005042MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005043 NexusInfo *nexus_info,ExceptionInfo *exception)
5044{
5045 CacheInfo
5046 *cache_info;
5047
5048 MagickBooleanType
5049 status;
5050
5051 /*
5052 Transfer pixels to the cache.
5053 */
5054 assert(image != (Image *) NULL);
5055 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005056 if (image->cache == (Cache) NULL)
5057 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5058 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005059 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005060 if (cache_info->type == UndefinedCache)
5061 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005062 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005063 return(MagickTrue);
5064 assert(cache_info->signature == MagickSignature);
5065 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005066 if ((cache_info->metacontent_extent != 0) &&
5067 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005068 return(MagickFalse);
5069 return(status);
5070}
5071
5072/*
5073%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5074% %
5075% %
5076% %
5077+ S y n c A u t h e n t i c P i x e l C a c h e %
5078% %
5079% %
5080% %
5081%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5082%
5083% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5084% or disk cache. The method returns MagickTrue if the pixel region is synced,
5085% otherwise MagickFalse.
5086%
5087% The format of the SyncAuthenticPixelsCache() method is:
5088%
5089% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5090% ExceptionInfo *exception)
5091%
5092% A description of each parameter follows:
5093%
5094% o image: the image.
5095%
5096% o exception: return any errors or warnings in this structure.
5097%
5098*/
5099static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5100 ExceptionInfo *exception)
5101{
5102 CacheInfo
5103 *cache_info;
5104
cristy5c9e6f22010-09-17 17:31:01 +00005105 const int
5106 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005107
cristy4c08aed2011-07-01 19:47:50 +00005108 MagickBooleanType
5109 status;
5110
cristye7cc7cf2010-09-21 13:26:47 +00005111 assert(image != (Image *) NULL);
5112 assert(image->signature == MagickSignature);
5113 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005114 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005115 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005116 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005117 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5118 exception);
5119 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005120}
5121
5122/*
5123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5124% %
5125% %
5126% %
5127% S y n c A u t h e n t i c P i x e l s %
5128% %
5129% %
5130% %
5131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5132%
5133% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5134% The method returns MagickTrue if the pixel region is flushed, otherwise
5135% MagickFalse.
5136%
5137% The format of the SyncAuthenticPixels() method is:
5138%
5139% MagickBooleanType SyncAuthenticPixels(Image *image,
5140% ExceptionInfo *exception)
5141%
5142% A description of each parameter follows:
5143%
5144% o image: the image.
5145%
5146% o exception: return any errors or warnings in this structure.
5147%
5148*/
5149MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5150 ExceptionInfo *exception)
5151{
5152 CacheInfo
5153 *cache_info;
5154
cristy2036f5c2010-09-19 21:18:17 +00005155 const int
5156 id = GetOpenMPThreadId();
5157
cristy4c08aed2011-07-01 19:47:50 +00005158 MagickBooleanType
5159 status;
5160
cristy3ed852e2009-09-05 21:47:34 +00005161 assert(image != (Image *) NULL);
5162 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005163 assert(image->cache != (Cache) NULL);
5164 cache_info=(CacheInfo *) image->cache;
5165 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005166 if (cache_info->methods.sync_authentic_pixels_handler !=
5167 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005168 {
5169 status=cache_info->methods.sync_authentic_pixels_handler(image,
5170 exception);
5171 return(status);
5172 }
cristy2036f5c2010-09-19 21:18:17 +00005173 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005174 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5175 exception);
5176 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005177}
5178
5179/*
5180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5181% %
5182% %
5183% %
cristyd1dd6e42011-09-04 01:46:08 +00005184+ 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 +00005185% %
5186% %
5187% %
5188%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5189%
5190% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5191% The method returns MagickTrue if the pixel region is flushed, otherwise
5192% MagickFalse.
5193%
5194% The format of the SyncImagePixelCache() method is:
5195%
5196% MagickBooleanType SyncImagePixelCache(Image *image,
5197% ExceptionInfo *exception)
5198%
5199% A description of each parameter follows:
5200%
5201% o image: the image.
5202%
5203% o exception: return any errors or warnings in this structure.
5204%
5205*/
cristyd1dd6e42011-09-04 01:46:08 +00005206MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005207 ExceptionInfo *exception)
5208{
5209 CacheInfo
5210 *cache_info;
5211
5212 assert(image != (Image *) NULL);
5213 assert(exception != (ExceptionInfo *) NULL);
5214 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5215 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5216}
5217
5218/*
5219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5220% %
5221% %
5222% %
cristy4c08aed2011-07-01 19:47:50 +00005223+ 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 +00005224% %
5225% %
5226% %
5227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5228%
cristy4c08aed2011-07-01 19:47:50 +00005229% WritePixelCacheMetacontent() writes the meta-content to the specified region
5230% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005231%
cristy4c08aed2011-07-01 19:47:50 +00005232% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005233%
cristy4c08aed2011-07-01 19:47:50 +00005234% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005235% NexusInfo *nexus_info,ExceptionInfo *exception)
5236%
5237% A description of each parameter follows:
5238%
5239% o cache_info: the pixel cache.
5240%
cristy4c08aed2011-07-01 19:47:50 +00005241% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005242%
5243% o exception: return any errors or warnings in this structure.
5244%
5245*/
cristy4c08aed2011-07-01 19:47:50 +00005246static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005247 NexusInfo *nexus_info,ExceptionInfo *exception)
5248{
5249 MagickOffsetType
5250 count,
5251 offset;
5252
5253 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005254 extent,
5255 length;
cristy3ed852e2009-09-05 21:47:34 +00005256
cristy4c08aed2011-07-01 19:47:50 +00005257 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005258 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005259
cristybb503372010-05-27 20:51:26 +00005260 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005261 y;
5262
cristybb503372010-05-27 20:51:26 +00005263 size_t
cristy3ed852e2009-09-05 21:47:34 +00005264 rows;
5265
cristy4c08aed2011-07-01 19:47:50 +00005266 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005267 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005268 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005269 return(MagickTrue);
5270 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5271 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005272 length=(MagickSizeType) nexus_info->region.width*
5273 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005274 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005275 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005276 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005277 switch (cache_info->type)
5278 {
5279 case MemoryCache:
5280 case MapCache:
5281 {
cristy4c08aed2011-07-01 19:47:50 +00005282 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005283 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005284
5285 /*
cristy4c08aed2011-07-01 19:47:50 +00005286 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005287 */
cristydd341db2010-03-04 19:06:38 +00005288 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005289 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005290 {
cristy48078b12010-09-23 17:11:01 +00005291 length=extent;
cristydd341db2010-03-04 19:06:38 +00005292 rows=1UL;
5293 }
cristy4c08aed2011-07-01 19:47:50 +00005294 q=(unsigned char *) cache_info->metacontent+offset*
5295 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005296 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005297 {
cristy8f036fe2010-09-18 02:02:00 +00005298 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005299 p+=nexus_info->region.width*cache_info->metacontent_extent;
5300 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005301 }
5302 break;
5303 }
5304 case DiskCache:
5305 {
5306 /*
cristy4c08aed2011-07-01 19:47:50 +00005307 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005308 */
5309 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5310 {
5311 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5312 cache_info->cache_filename);
5313 return(MagickFalse);
5314 }
cristydd341db2010-03-04 19:06:38 +00005315 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005316 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005317 {
cristy48078b12010-09-23 17:11:01 +00005318 length=extent;
cristydd341db2010-03-04 19:06:38 +00005319 rows=1UL;
5320 }
cristy48078b12010-09-23 17:11:01 +00005321 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005322 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005323 {
cristy48078b12010-09-23 17:11:01 +00005324 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005325 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005326 cache_info->metacontent_extent,length,(const unsigned char *) p);
5327 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005328 break;
cristy4c08aed2011-07-01 19:47:50 +00005329 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005330 offset+=cache_info->columns;
5331 }
cristyc11dace2012-01-24 16:39:46 +00005332 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5333 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005334 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005335 {
5336 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5337 cache_info->cache_filename);
5338 return(MagickFalse);
5339 }
5340 break;
5341 }
5342 default:
5343 break;
5344 }
5345 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005346 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005347 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005348 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005349 nexus_info->region.width,(double) nexus_info->region.height,(double)
5350 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005351 return(MagickTrue);
5352}
5353
5354/*
5355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5356% %
5357% %
5358% %
5359+ W r i t e C a c h e P i x e l s %
5360% %
5361% %
5362% %
5363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5364%
5365% WritePixelCachePixels() writes image pixels to the specified region of the
5366% pixel cache.
5367%
5368% The format of the WritePixelCachePixels() method is:
5369%
5370% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5371% NexusInfo *nexus_info,ExceptionInfo *exception)
5372%
5373% A description of each parameter follows:
5374%
5375% o cache_info: the pixel cache.
5376%
5377% o nexus_info: the cache nexus to write the pixels.
5378%
5379% o exception: return any errors or warnings in this structure.
5380%
5381*/
5382static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5383 NexusInfo *nexus_info,ExceptionInfo *exception)
5384{
5385 MagickOffsetType
5386 count,
5387 offset;
5388
5389 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005390 extent,
5391 length;
cristy3ed852e2009-09-05 21:47:34 +00005392
cristy4c08aed2011-07-01 19:47:50 +00005393 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005394 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005395
cristybb503372010-05-27 20:51:26 +00005396 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005397 y;
5398
cristybb503372010-05-27 20:51:26 +00005399 size_t
cristy3ed852e2009-09-05 21:47:34 +00005400 rows;
5401
cristy4c08aed2011-07-01 19:47:50 +00005402 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005403 return(MagickTrue);
5404 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5405 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005406 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005407 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005408 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005409 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005410 p=nexus_info->pixels;
5411 switch (cache_info->type)
5412 {
5413 case MemoryCache:
5414 case MapCache:
5415 {
cristy4c08aed2011-07-01 19:47:50 +00005416 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005417 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005418
5419 /*
5420 Write pixels to memory.
5421 */
cristydd341db2010-03-04 19:06:38 +00005422 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005423 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005424 {
cristy48078b12010-09-23 17:11:01 +00005425 length=extent;
cristydd341db2010-03-04 19:06:38 +00005426 rows=1UL;
5427 }
cristyed231572011-07-14 02:18:59 +00005428 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005429 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005430 {
cristy8f036fe2010-09-18 02:02:00 +00005431 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005432 p+=nexus_info->region.width*cache_info->number_channels;
5433 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005434 }
5435 break;
5436 }
5437 case DiskCache:
5438 {
5439 /*
5440 Write pixels to disk.
5441 */
5442 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5443 {
5444 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5445 cache_info->cache_filename);
5446 return(MagickFalse);
5447 }
cristydd341db2010-03-04 19:06:38 +00005448 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005449 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005450 {
cristy48078b12010-09-23 17:11:01 +00005451 length=extent;
cristydd341db2010-03-04 19:06:38 +00005452 rows=1UL;
5453 }
cristybb503372010-05-27 20:51:26 +00005454 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005455 {
5456 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005457 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005458 p);
5459 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005460 break;
cristyed231572011-07-14 02:18:59 +00005461 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005462 offset+=cache_info->columns;
5463 }
cristyc11dace2012-01-24 16:39:46 +00005464 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5465 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005466 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005467 {
5468 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5469 cache_info->cache_filename);
5470 return(MagickFalse);
5471 }
5472 break;
5473 }
5474 default:
5475 break;
5476 }
5477 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005478 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005479 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005480 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005481 nexus_info->region.width,(double) nexus_info->region.height,(double)
5482 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005483 return(MagickTrue);
5484}