blob: 7bd50bd683e16b1c356108de251122d768a0cc29 [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 /*
1906 Set the exire time in seconds.
1907 */
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 Image
1923 clone_image;
1924
1925 CacheInfo
1926 *clone_info;
1927
1928 /*
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 {
cristy979bf772011-08-08 00:04:15 +00001943 if (cache_info->mode == ReadMode)
1944 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001945 destroy=MagickTrue;
1946 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001947 }
1948 }
cristyceb55ee2010-11-06 16:05:49 +00001949 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001950 }
cristyceb55ee2010-11-06 16:05:49 +00001951 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001952 }
cristy4320e0e2009-09-10 15:00:08 +00001953 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001954 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001955 if (status != MagickFalse)
1956 {
1957 /*
1958 Ensure the image matches the pixel cache morphology.
1959 */
1960 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001961 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001962 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001963 {
1964 status=OpenPixelCache(image,IOMode,exception);
1965 cache_info=(CacheInfo *) image->cache;
1966 if (cache_info->type == DiskCache)
1967 (void) ClosePixelCacheOnDisk(cache_info);
1968 }
cristy3ed852e2009-09-05 21:47:34 +00001969 }
cristyf84a1932010-01-03 18:00:18 +00001970 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001971 if (status == MagickFalse)
1972 return((Cache) NULL);
1973 return(image->cache);
1974}
1975
1976/*
1977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1978% %
1979% %
1980% %
cristyce1fe792012-05-16 15:58:37 +00001981+ G e t I m a g e P i x e l C a c h e T y p e %
1982% %
1983% %
1984% %
1985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986%
1987% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1988% DiskCache, MemoryCache, MapCache, or PingCache.
1989%
1990% The format of the GetImagePixelCacheType() method is:
1991%
cristy5bef4cd2012-05-17 18:08:56 +00001992% CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001993%
1994% A description of each parameter follows:
1995%
1996% o image: the image.
1997%
1998*/
cristy5bef4cd2012-05-17 18:08:56 +00001999MagickExport CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00002000{
cristy238287d2012-05-17 18:16:56 +00002001 CacheInfo
2002 *cache_info;
2003
2004 assert(image != (Image *) NULL);
2005 assert(image->signature == MagickSignature);
2006 assert(image->cache != (Cache) NULL);
2007 cache_info=(CacheInfo *) image->cache;
2008 assert(cache_info->signature == MagickSignature);
2009 return(cache_info->type);
cristyce1fe792012-05-16 15:58:37 +00002010}
2011
2012/*
2013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2014% %
2015% %
2016% %
cristy3ed852e2009-09-05 21:47:34 +00002017% G e t O n e A u t h e n t i c P i x e l %
2018% %
2019% %
2020% %
2021%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2022%
2023% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2024% location. The image background color is returned if an error occurs.
2025%
2026% The format of the GetOneAuthenticPixel() method is:
2027%
cristybb503372010-05-27 20:51:26 +00002028% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002029% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002030%
2031% A description of each parameter follows:
2032%
2033% o image: the image.
2034%
2035% o x,y: These values define the location of the pixel to return.
2036%
2037% o pixel: return a pixel at the specified (x,y) location.
2038%
2039% o exception: return any errors or warnings in this structure.
2040%
2041*/
cristyacbbb7c2010-06-30 18:56:48 +00002042MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002043 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002044{
2045 CacheInfo
2046 *cache_info;
2047
cristy4c08aed2011-07-01 19:47:50 +00002048 register Quantum
2049 *q;
cristy2036f5c2010-09-19 21:18:17 +00002050
cristy2ed42f62011-10-02 19:49:57 +00002051 register ssize_t
2052 i;
2053
cristy3ed852e2009-09-05 21:47:34 +00002054 assert(image != (Image *) NULL);
2055 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002056 assert(image->cache != (Cache) NULL);
2057 cache_info=(CacheInfo *) image->cache;
2058 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002059 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002060 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2061 (GetOneAuthenticPixelFromHandler) NULL)
2062 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2063 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002064 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2065 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002066 {
cristy9e0719b2011-12-29 03:45:45 +00002067 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2068 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2069 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2070 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2071 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002072 return(MagickFalse);
2073 }
2074 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2075 {
2076 PixelChannel
2077 channel;
2078
cristycf1296e2012-08-26 23:40:49 +00002079 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002080 pixel[channel]=q[i];
2081 }
cristy2036f5c2010-09-19 21:18:17 +00002082 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002083}
2084
2085/*
2086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2087% %
2088% %
2089% %
2090+ 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 %
2091% %
2092% %
2093% %
2094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2095%
2096% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2097% location. The image background color is returned if an error occurs.
2098%
2099% The format of the GetOneAuthenticPixelFromCache() method is:
2100%
2101% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002102% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002103% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002104%
2105% A description of each parameter follows:
2106%
2107% o image: the image.
2108%
2109% o x,y: These values define the location of the pixel to return.
2110%
2111% o pixel: return a pixel at the specified (x,y) location.
2112%
2113% o exception: return any errors or warnings in this structure.
2114%
2115*/
2116static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002117 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002118{
cristy098f78c2010-09-23 17:28:44 +00002119 CacheInfo
2120 *cache_info;
2121
2122 const int
2123 id = GetOpenMPThreadId();
2124
cristy4c08aed2011-07-01 19:47:50 +00002125 register Quantum
2126 *q;
cristy3ed852e2009-09-05 21:47:34 +00002127
cristy2ed42f62011-10-02 19:49:57 +00002128 register ssize_t
2129 i;
2130
cristy0158a4b2010-09-20 13:59:45 +00002131 assert(image != (const Image *) NULL);
2132 assert(image->signature == MagickSignature);
2133 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002134 cache_info=(CacheInfo *) image->cache;
2135 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002136 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002137 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002138 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2139 exception);
2140 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002141 {
cristy9e0719b2011-12-29 03:45:45 +00002142 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2143 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2144 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2145 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2146 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002147 return(MagickFalse);
2148 }
2149 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2150 {
2151 PixelChannel
2152 channel;
2153
cristycf1296e2012-08-26 23:40:49 +00002154 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002155 pixel[channel]=q[i];
2156 }
cristy3ed852e2009-09-05 21:47:34 +00002157 return(MagickTrue);
2158}
2159
2160/*
2161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2162% %
2163% %
2164% %
cristy3ed852e2009-09-05 21:47:34 +00002165% G e t O n e V i r t u a l P i x e l %
2166% %
2167% %
2168% %
2169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2170%
2171% GetOneVirtualPixel() returns a single virtual pixel at the specified
2172% (x,y) location. The image background color is returned if an error occurs.
2173% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2174%
2175% The format of the GetOneVirtualPixel() method is:
2176%
cristybb503372010-05-27 20:51:26 +00002177% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002178% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002179%
2180% A description of each parameter follows:
2181%
2182% o image: the image.
2183%
2184% o x,y: These values define the location of the pixel to return.
2185%
2186% o pixel: return a pixel at the specified (x,y) location.
2187%
2188% o exception: return any errors or warnings in this structure.
2189%
2190*/
2191MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002192 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002193{
cristy3ed852e2009-09-05 21:47:34 +00002194 CacheInfo
2195 *cache_info;
2196
cristy0158a4b2010-09-20 13:59:45 +00002197 const int
2198 id = GetOpenMPThreadId();
2199
cristy4c08aed2011-07-01 19:47:50 +00002200 const Quantum
2201 *p;
cristy2036f5c2010-09-19 21:18:17 +00002202
cristy2ed42f62011-10-02 19:49:57 +00002203 register ssize_t
2204 i;
2205
cristy3ed852e2009-09-05 21:47:34 +00002206 assert(image != (const Image *) NULL);
2207 assert(image->signature == MagickSignature);
2208 assert(image->cache != (Cache) NULL);
2209 cache_info=(CacheInfo *) image->cache;
2210 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002211 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002212 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2213 (GetOneVirtualPixelFromHandler) NULL)
2214 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2215 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002216 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002217 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002218 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002219 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002220 {
cristy9e0719b2011-12-29 03:45:45 +00002221 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2222 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2223 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2224 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2225 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002226 return(MagickFalse);
2227 }
2228 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2229 {
2230 PixelChannel
2231 channel;
2232
cristycf1296e2012-08-26 23:40:49 +00002233 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002234 pixel[channel]=p[i];
2235 }
cristy2036f5c2010-09-19 21:18:17 +00002236 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002237}
2238
2239/*
2240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2241% %
2242% %
2243% %
2244+ 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 %
2245% %
2246% %
2247% %
2248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2249%
2250% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2251% specified (x,y) location. The image background color is returned if an
2252% error occurs.
2253%
2254% The format of the GetOneVirtualPixelFromCache() method is:
2255%
2256% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002257% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002258% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002259%
2260% A description of each parameter follows:
2261%
2262% o image: the image.
2263%
2264% o virtual_pixel_method: the virtual pixel method.
2265%
2266% o x,y: These values define the location of the pixel to return.
2267%
2268% o pixel: return a pixel at the specified (x,y) location.
2269%
2270% o exception: return any errors or warnings in this structure.
2271%
2272*/
2273static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002274 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002275 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002276{
cristy0158a4b2010-09-20 13:59:45 +00002277 CacheInfo
2278 *cache_info;
2279
2280 const int
2281 id = GetOpenMPThreadId();
2282
cristy4c08aed2011-07-01 19:47:50 +00002283 const Quantum
2284 *p;
cristy3ed852e2009-09-05 21:47:34 +00002285
cristy2ed42f62011-10-02 19:49:57 +00002286 register ssize_t
2287 i;
2288
cristye7cc7cf2010-09-21 13:26:47 +00002289 assert(image != (const Image *) NULL);
2290 assert(image->signature == MagickSignature);
2291 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002292 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002293 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002294 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002295 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002296 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002297 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002298 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002299 {
cristy9e0719b2011-12-29 03:45:45 +00002300 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2301 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2302 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2303 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2304 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002305 return(MagickFalse);
2306 }
2307 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2308 {
2309 PixelChannel
2310 channel;
2311
cristycf1296e2012-08-26 23:40:49 +00002312 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002313 pixel[channel]=p[i];
2314 }
cristy3ed852e2009-09-05 21:47:34 +00002315 return(MagickTrue);
2316}
2317
2318/*
2319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2320% %
2321% %
2322% %
cristy3aa93752011-12-18 15:54:24 +00002323% G e t O n e V i r t u a l P i x e l I n f o %
2324% %
2325% %
2326% %
2327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2328%
2329% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2330% location. The image background color is returned if an error occurs. If
2331% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2332%
2333% The format of the GetOneVirtualPixelInfo() method is:
2334%
2335% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2336% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2337% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2338%
2339% A description of each parameter follows:
2340%
2341% o image: the image.
2342%
2343% o virtual_pixel_method: the virtual pixel method.
2344%
2345% o x,y: these values define the location of the pixel to return.
2346%
2347% o pixel: return a pixel at the specified (x,y) location.
2348%
2349% o exception: return any errors or warnings in this structure.
2350%
2351*/
2352MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2353 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2354 PixelInfo *pixel,ExceptionInfo *exception)
2355{
2356 CacheInfo
2357 *cache_info;
2358
2359 const int
2360 id = GetOpenMPThreadId();
2361
2362 register const Quantum
2363 *p;
2364
2365 assert(image != (const Image *) NULL);
2366 assert(image->signature == MagickSignature);
2367 assert(image->cache != (Cache) NULL);
2368 cache_info=(CacheInfo *) image->cache;
2369 assert(cache_info->signature == MagickSignature);
2370 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002371 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002372 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2373 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002374 if (p == (const Quantum *) NULL)
2375 return(MagickFalse);
2376 GetPixelInfoPixel(image,p,pixel);
2377 return(MagickTrue);
2378}
2379
2380/*
2381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2382% %
2383% %
2384% %
cristy3ed852e2009-09-05 21:47:34 +00002385+ G e t P i x e l C a c h e C o l o r s p a c e %
2386% %
2387% %
2388% %
2389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2390%
2391% GetPixelCacheColorspace() returns the class type of the pixel cache.
2392%
2393% The format of the GetPixelCacheColorspace() method is:
2394%
2395% Colorspace GetPixelCacheColorspace(Cache cache)
2396%
2397% A description of each parameter follows:
2398%
2399% o cache: the pixel cache.
2400%
2401*/
cristya6577ff2011-09-02 19:54:26 +00002402MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002403{
2404 CacheInfo
2405 *cache_info;
2406
2407 assert(cache != (Cache) NULL);
2408 cache_info=(CacheInfo *) cache;
2409 assert(cache_info->signature == MagickSignature);
2410 if (cache_info->debug != MagickFalse)
2411 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2412 cache_info->filename);
2413 return(cache_info->colorspace);
2414}
2415
2416/*
2417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2418% %
2419% %
2420% %
2421+ G e t P i x e l C a c h e M e t h o d s %
2422% %
2423% %
2424% %
2425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2426%
2427% GetPixelCacheMethods() initializes the CacheMethods structure.
2428%
2429% The format of the GetPixelCacheMethods() method is:
2430%
2431% void GetPixelCacheMethods(CacheMethods *cache_methods)
2432%
2433% A description of each parameter follows:
2434%
2435% o cache_methods: Specifies a pointer to a CacheMethods structure.
2436%
2437*/
cristya6577ff2011-09-02 19:54:26 +00002438MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002439{
2440 assert(cache_methods != (CacheMethods *) NULL);
2441 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2442 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2443 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002444 cache_methods->get_virtual_metacontent_from_handler=
2445 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002446 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2447 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002448 cache_methods->get_authentic_metacontent_from_handler=
2449 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002450 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2451 cache_methods->get_one_authentic_pixel_from_handler=
2452 GetOneAuthenticPixelFromCache;
2453 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2454 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2455 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2456}
2457
2458/*
2459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2460% %
2461% %
2462% %
2463+ G e t P i x e l C a c h e N e x u s E x t e n t %
2464% %
2465% %
2466% %
2467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2468%
cristy4c08aed2011-07-01 19:47:50 +00002469% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2470% corresponding with the last call to SetPixelCacheNexusPixels() or
2471% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002472%
2473% The format of the GetPixelCacheNexusExtent() method is:
2474%
2475% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2476% NexusInfo *nexus_info)
2477%
2478% A description of each parameter follows:
2479%
2480% o nexus_info: the nexus info.
2481%
2482*/
cristya6577ff2011-09-02 19:54:26 +00002483MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002484 NexusInfo *nexus_info)
2485{
2486 CacheInfo
2487 *cache_info;
2488
2489 MagickSizeType
2490 extent;
2491
cristy9f027d12011-09-21 01:17:17 +00002492 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002493 cache_info=(CacheInfo *) cache;
2494 assert(cache_info->signature == MagickSignature);
2495 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2496 if (extent == 0)
2497 return((MagickSizeType) cache_info->columns*cache_info->rows);
2498 return(extent);
2499}
2500
2501/*
2502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2503% %
2504% %
2505% %
cristy4c08aed2011-07-01 19:47:50 +00002506+ 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 +00002507% %
2508% %
2509% %
2510%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2511%
cristy4c08aed2011-07-01 19:47:50 +00002512% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2513% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002514%
cristy4c08aed2011-07-01 19:47:50 +00002515% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002516%
cristy4c08aed2011-07-01 19:47:50 +00002517% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002518% NexusInfo *nexus_info)
2519%
2520% A description of each parameter follows:
2521%
2522% o cache: the pixel cache.
2523%
cristy4c08aed2011-07-01 19:47:50 +00002524% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002525%
2526*/
cristya6577ff2011-09-02 19:54:26 +00002527MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002528 NexusInfo *nexus_info)
2529{
2530 CacheInfo
2531 *cache_info;
2532
cristy9f027d12011-09-21 01:17:17 +00002533 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002534 cache_info=(CacheInfo *) cache;
2535 assert(cache_info->signature == MagickSignature);
2536 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002537 return((void *) NULL);
2538 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002539}
2540
2541/*
2542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543% %
2544% %
2545% %
2546+ G e t P i x e l C a c h e N e x u s P i x e l s %
2547% %
2548% %
2549% %
2550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2551%
2552% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2553% cache nexus.
2554%
2555% The format of the GetPixelCacheNexusPixels() method is:
2556%
cristy4c08aed2011-07-01 19:47:50 +00002557% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002558% NexusInfo *nexus_info)
2559%
2560% A description of each parameter follows:
2561%
2562% o cache: the pixel cache.
2563%
2564% o nexus_info: the cache nexus to return the pixels.
2565%
2566*/
cristya6577ff2011-09-02 19:54:26 +00002567MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002568 NexusInfo *nexus_info)
2569{
2570 CacheInfo
2571 *cache_info;
2572
cristy9f027d12011-09-21 01:17:17 +00002573 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002574 cache_info=(CacheInfo *) cache;
2575 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002576 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002577 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002578 return(nexus_info->pixels);
2579}
2580
2581/*
2582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2583% %
2584% %
2585% %
cristy056ba772010-01-02 23:33:54 +00002586+ G e t P i x e l C a c h e P i x e l s %
2587% %
2588% %
2589% %
2590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591%
2592% GetPixelCachePixels() returns the pixels associated with the specified image.
2593%
2594% The format of the GetPixelCachePixels() method is:
2595%
cristyf84a1932010-01-03 18:00:18 +00002596% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2597% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002598%
2599% A description of each parameter follows:
2600%
2601% o image: the image.
2602%
2603% o length: the pixel cache length.
2604%
cristyf84a1932010-01-03 18:00:18 +00002605% o exception: return any errors or warnings in this structure.
2606%
cristy056ba772010-01-02 23:33:54 +00002607*/
cristyd1dd6e42011-09-04 01:46:08 +00002608MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002609 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002610{
2611 CacheInfo
2612 *cache_info;
2613
2614 assert(image != (const Image *) NULL);
2615 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002616 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002617 assert(length != (MagickSizeType *) NULL);
2618 assert(exception != (ExceptionInfo *) NULL);
2619 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002620 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002621 assert(cache_info->signature == MagickSignature);
2622 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002623 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002624 return((void *) NULL);
2625 *length=cache_info->length;
2626 return((void *) cache_info->pixels);
2627}
2628
2629/*
2630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2631% %
2632% %
2633% %
cristyb32b90a2009-09-07 21:45:48 +00002634+ 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 +00002635% %
2636% %
2637% %
2638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2639%
2640% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2641%
2642% The format of the GetPixelCacheStorageClass() method is:
2643%
2644% ClassType GetPixelCacheStorageClass(Cache cache)
2645%
2646% A description of each parameter follows:
2647%
2648% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2649%
2650% o cache: the pixel cache.
2651%
2652*/
cristya6577ff2011-09-02 19:54:26 +00002653MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002654{
2655 CacheInfo
2656 *cache_info;
2657
2658 assert(cache != (Cache) NULL);
2659 cache_info=(CacheInfo *) cache;
2660 assert(cache_info->signature == MagickSignature);
2661 if (cache_info->debug != MagickFalse)
2662 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2663 cache_info->filename);
2664 return(cache_info->storage_class);
2665}
2666
2667/*
2668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2669% %
2670% %
2671% %
cristyb32b90a2009-09-07 21:45:48 +00002672+ G e t P i x e l C a c h e T i l e S i z e %
2673% %
2674% %
2675% %
2676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2677%
2678% GetPixelCacheTileSize() returns the pixel cache tile size.
2679%
2680% The format of the GetPixelCacheTileSize() method is:
2681%
cristybb503372010-05-27 20:51:26 +00002682% void GetPixelCacheTileSize(const Image *image,size_t *width,
2683% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002684%
2685% A description of each parameter follows:
2686%
2687% o image: the image.
2688%
2689% o width: the optimize cache tile width in pixels.
2690%
2691% o height: the optimize cache tile height in pixels.
2692%
2693*/
cristya6577ff2011-09-02 19:54:26 +00002694MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002695 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002696{
cristy4c08aed2011-07-01 19:47:50 +00002697 CacheInfo
2698 *cache_info;
2699
cristyb32b90a2009-09-07 21:45:48 +00002700 assert(image != (Image *) NULL);
2701 assert(image->signature == MagickSignature);
2702 if (image->debug != MagickFalse)
2703 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002704 cache_info=(CacheInfo *) image->cache;
2705 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002706 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristy238287d2012-05-17 18:16:56 +00002707 if (GetImagePixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002708 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002709 *height=(*width);
2710}
2711
2712/*
2713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714% %
2715% %
2716% %
cristy3ed852e2009-09-05 21:47:34 +00002717+ 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 %
2718% %
2719% %
2720% %
2721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722%
2723% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2724% pixel cache. A virtual pixel is any pixel access that is outside the
2725% boundaries of the image cache.
2726%
2727% The format of the GetPixelCacheVirtualMethod() method is:
2728%
2729% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2730%
2731% A description of each parameter follows:
2732%
2733% o image: the image.
2734%
2735*/
cristyd1dd6e42011-09-04 01:46:08 +00002736MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002737{
2738 CacheInfo
2739 *cache_info;
2740
2741 assert(image != (Image *) NULL);
2742 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002743 assert(image->cache != (Cache) NULL);
2744 cache_info=(CacheInfo *) image->cache;
2745 assert(cache_info->signature == MagickSignature);
2746 return(cache_info->virtual_pixel_method);
2747}
2748
2749/*
2750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2751% %
2752% %
2753% %
cristy4c08aed2011-07-01 19:47:50 +00002754+ 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 +00002755% %
2756% %
2757% %
2758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2759%
cristy4c08aed2011-07-01 19:47:50 +00002760% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2761% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002762%
cristy4c08aed2011-07-01 19:47:50 +00002763% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002764%
cristy4c08aed2011-07-01 19:47:50 +00002765% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002766%
2767% A description of each parameter follows:
2768%
2769% o image: the image.
2770%
2771*/
cristy4c08aed2011-07-01 19:47:50 +00002772static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002773{
2774 CacheInfo
2775 *cache_info;
2776
cristy5c9e6f22010-09-17 17:31:01 +00002777 const int
2778 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002779
cristy4c08aed2011-07-01 19:47:50 +00002780 const void
2781 *metacontent;
2782
cristye7cc7cf2010-09-21 13:26:47 +00002783 assert(image != (const Image *) NULL);
2784 assert(image->signature == MagickSignature);
2785 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002786 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002787 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002788 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002789 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2790 cache_info->nexus_info[id]);
2791 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002792}
2793
2794/*
2795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796% %
2797% %
2798% %
cristy4c08aed2011-07-01 19:47:50 +00002799+ 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 +00002800% %
2801% %
2802% %
2803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804%
cristy4c08aed2011-07-01 19:47:50 +00002805% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2806% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002807%
cristy4c08aed2011-07-01 19:47:50 +00002808% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002809%
cristy4c08aed2011-07-01 19:47:50 +00002810% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002811% NexusInfo *nexus_info)
2812%
2813% A description of each parameter follows:
2814%
2815% o cache: the pixel cache.
2816%
cristy4c08aed2011-07-01 19:47:50 +00002817% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002818%
2819*/
cristya6577ff2011-09-02 19:54:26 +00002820MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002821 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002822{
2823 CacheInfo
2824 *cache_info;
2825
cristye7cc7cf2010-09-21 13:26:47 +00002826 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002827 cache_info=(CacheInfo *) cache;
2828 assert(cache_info->signature == MagickSignature);
2829 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002830 return((void *) NULL);
2831 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002832}
2833
2834/*
2835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2836% %
2837% %
2838% %
cristy4c08aed2011-07-01 19:47:50 +00002839% 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 +00002840% %
2841% %
2842% %
2843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2844%
cristy4c08aed2011-07-01 19:47:50 +00002845% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2846% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2847% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002848%
cristy4c08aed2011-07-01 19:47:50 +00002849% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002850%
cristy4c08aed2011-07-01 19:47:50 +00002851% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002852%
2853% A description of each parameter follows:
2854%
2855% o image: the image.
2856%
2857*/
cristy4c08aed2011-07-01 19:47:50 +00002858MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002859{
2860 CacheInfo
2861 *cache_info;
2862
cristy2036f5c2010-09-19 21:18:17 +00002863 const int
2864 id = GetOpenMPThreadId();
2865
cristy4c08aed2011-07-01 19:47:50 +00002866 const void
2867 *metacontent;
2868
cristy3ed852e2009-09-05 21:47:34 +00002869 assert(image != (const Image *) NULL);
2870 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002871 assert(image->cache != (Cache) NULL);
2872 cache_info=(CacheInfo *) image->cache;
2873 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002874 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002875 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002876 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002877 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002878 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2879 cache_info->nexus_info[id]);
2880 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002881}
2882
2883/*
2884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885% %
2886% %
2887% %
2888+ 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 %
2889% %
2890% %
2891% %
2892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2893%
2894% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2895% pixel cache as defined by the geometry parameters. A pointer to the pixels
2896% is returned if the pixels are transferred, otherwise a NULL is returned.
2897%
2898% The format of the GetVirtualPixelsFromNexus() method is:
2899%
cristy4c08aed2011-07-01 19:47:50 +00002900% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002901% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002902% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2903% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002904%
2905% A description of each parameter follows:
2906%
2907% o image: the image.
2908%
2909% o virtual_pixel_method: the virtual pixel method.
2910%
2911% o x,y,columns,rows: These values define the perimeter of a region of
2912% pixels.
2913%
2914% o nexus_info: the cache nexus to acquire.
2915%
2916% o exception: return any errors or warnings in this structure.
2917%
2918*/
2919
cristybb503372010-05-27 20:51:26 +00002920static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002921 DitherMatrix[64] =
2922 {
2923 0, 48, 12, 60, 3, 51, 15, 63,
2924 32, 16, 44, 28, 35, 19, 47, 31,
2925 8, 56, 4, 52, 11, 59, 7, 55,
2926 40, 24, 36, 20, 43, 27, 39, 23,
2927 2, 50, 14, 62, 1, 49, 13, 61,
2928 34, 18, 46, 30, 33, 17, 45, 29,
2929 10, 58, 6, 54, 9, 57, 5, 53,
2930 42, 26, 38, 22, 41, 25, 37, 21
2931 };
2932
cristybb503372010-05-27 20:51:26 +00002933static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002934{
cristybb503372010-05-27 20:51:26 +00002935 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002936 index;
2937
2938 index=x+DitherMatrix[x & 0x07]-32L;
2939 if (index < 0L)
2940 return(0L);
cristybb503372010-05-27 20:51:26 +00002941 if (index >= (ssize_t) columns)
2942 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002943 return(index);
2944}
2945
cristybb503372010-05-27 20:51:26 +00002946static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002947{
cristybb503372010-05-27 20:51:26 +00002948 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002949 index;
2950
2951 index=y+DitherMatrix[y & 0x07]-32L;
2952 if (index < 0L)
2953 return(0L);
cristybb503372010-05-27 20:51:26 +00002954 if (index >= (ssize_t) rows)
2955 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002956 return(index);
2957}
2958
cristybb503372010-05-27 20:51:26 +00002959static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002960{
2961 if (x < 0L)
2962 return(0L);
cristybb503372010-05-27 20:51:26 +00002963 if (x >= (ssize_t) columns)
2964 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002965 return(x);
2966}
2967
cristybb503372010-05-27 20:51:26 +00002968static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002969{
2970 if (y < 0L)
2971 return(0L);
cristybb503372010-05-27 20:51:26 +00002972 if (y >= (ssize_t) rows)
2973 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002974 return(y);
2975}
2976
cristybb503372010-05-27 20:51:26 +00002977static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002978{
cristybb503372010-05-27 20:51:26 +00002979 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002980}
2981
cristybb503372010-05-27 20:51:26 +00002982static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002983{
cristybb503372010-05-27 20:51:26 +00002984 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002985}
2986
cristybb503372010-05-27 20:51:26 +00002987static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2988 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002989{
2990 MagickModulo
2991 modulo;
2992
cristy6162bb42011-07-18 11:34:09 +00002993 /*
2994 Compute the remainder of dividing offset by extent. It returns not only
2995 the quotient (tile the offset falls in) but also the positive remainer
2996 within that tile such that 0 <= remainder < extent. This method is
2997 essentially a ldiv() using a floored modulo division rather than the
2998 normal default truncated modulo division.
2999 */
cristybb503372010-05-27 20:51:26 +00003000 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003001 if (offset < 0L)
3002 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003003 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003004 return(modulo);
3005}
3006
cristya6577ff2011-09-02 19:54:26 +00003007MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003008 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3009 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003010 ExceptionInfo *exception)
3011{
3012 CacheInfo
3013 *cache_info;
3014
3015 MagickOffsetType
3016 offset;
3017
3018 MagickSizeType
3019 length,
3020 number_pixels;
3021
3022 NexusInfo
3023 **virtual_nexus;
3024
cristy4c08aed2011-07-01 19:47:50 +00003025 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003026 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003027 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003028
3029 RectangleInfo
3030 region;
3031
cristy4c08aed2011-07-01 19:47:50 +00003032 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003033 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003034
cristy4c08aed2011-07-01 19:47:50 +00003035 register const void
3036 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003037
cristy4c08aed2011-07-01 19:47:50 +00003038 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003039 *restrict q;
3040
cristybb503372010-05-27 20:51:26 +00003041 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003042 i,
3043 u;
cristy3ed852e2009-09-05 21:47:34 +00003044
cristy4c08aed2011-07-01 19:47:50 +00003045 register unsigned char
3046 *restrict s;
3047
cristy105ba3c2011-07-18 02:28:38 +00003048 ssize_t
3049 v;
3050
cristy4c08aed2011-07-01 19:47:50 +00003051 void
cristy105ba3c2011-07-18 02:28:38 +00003052 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003053
cristy3ed852e2009-09-05 21:47:34 +00003054 /*
3055 Acquire pixels.
3056 */
cristye7cc7cf2010-09-21 13:26:47 +00003057 assert(image != (const Image *) NULL);
3058 assert(image->signature == MagickSignature);
3059 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003060 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003061 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003062 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003063 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003064 region.x=x;
3065 region.y=y;
3066 region.width=columns;
3067 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003068 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003069 if (pixels == (Quantum *) NULL)
3070 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003071 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003072 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3073 nexus_info->region.x;
3074 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3075 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003076 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3077 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003078 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3079 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003080 {
3081 MagickBooleanType
3082 status;
3083
3084 /*
3085 Pixel request is inside cache extents.
3086 */
cristy4c08aed2011-07-01 19:47:50 +00003087 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003088 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003089 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3090 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003091 return((const Quantum *) NULL);
3092 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003093 {
cristy4c08aed2011-07-01 19:47:50 +00003094 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003095 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003096 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003097 }
cristyacd2ed22011-08-30 01:44:23 +00003098 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003099 }
3100 /*
3101 Pixel request is outside cache extents.
3102 */
cristy4c08aed2011-07-01 19:47:50 +00003103 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003104 virtual_nexus=AcquirePixelCacheNexus(1);
3105 if (virtual_nexus == (NexusInfo **) NULL)
3106 {
cristy4c08aed2011-07-01 19:47:50 +00003107 if (virtual_nexus != (NexusInfo **) NULL)
3108 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003109 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003110 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003111 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003112 }
cristy105ba3c2011-07-18 02:28:38 +00003113 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3114 sizeof(*virtual_pixel));
3115 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003116 switch (virtual_pixel_method)
3117 {
cristy4c08aed2011-07-01 19:47:50 +00003118 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003119 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003121 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003122 case MaskVirtualPixelMethod:
3123 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003124 case EdgeVirtualPixelMethod:
3125 case CheckerTileVirtualPixelMethod:
3126 case HorizontalTileVirtualPixelMethod:
3127 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003128 {
cristy4c08aed2011-07-01 19:47:50 +00003129 if (cache_info->metacontent_extent != 0)
3130 {
cristy6162bb42011-07-18 11:34:09 +00003131 /*
3132 Acquire a metacontent buffer.
3133 */
cristya64b85d2011-09-14 01:02:31 +00003134 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003135 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003136 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003137 {
cristy4c08aed2011-07-01 19:47:50 +00003138 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3139 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003140 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003141 return((const Quantum *) NULL);
3142 }
cristy105ba3c2011-07-18 02:28:38 +00003143 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003144 cache_info->metacontent_extent);
3145 }
3146 switch (virtual_pixel_method)
3147 {
3148 case BlackVirtualPixelMethod:
3149 {
cristy30301712011-07-18 15:06:51 +00003150 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3151 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003152 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3153 break;
3154 }
3155 case GrayVirtualPixelMethod:
3156 {
cristy30301712011-07-18 15:06:51 +00003157 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003158 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3159 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003160 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3161 break;
3162 }
3163 case TransparentVirtualPixelMethod:
3164 {
cristy30301712011-07-18 15:06:51 +00003165 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3166 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003167 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3168 break;
3169 }
3170 case MaskVirtualPixelMethod:
3171 case WhiteVirtualPixelMethod:
3172 {
cristy30301712011-07-18 15:06:51 +00003173 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3174 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003175 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3176 break;
3177 }
3178 default:
3179 {
cristy9e0719b2011-12-29 03:45:45 +00003180 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3181 virtual_pixel);
3182 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3183 virtual_pixel);
3184 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3185 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003186 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3187 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003188 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3189 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003190 break;
3191 }
3192 }
cristy3ed852e2009-09-05 21:47:34 +00003193 break;
3194 }
3195 default:
cristy3ed852e2009-09-05 21:47:34 +00003196 break;
cristy3ed852e2009-09-05 21:47:34 +00003197 }
cristybb503372010-05-27 20:51:26 +00003198 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003199 {
cristybb503372010-05-27 20:51:26 +00003200 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003201 {
3202 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003203 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003204 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3205 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003206 {
3207 MagickModulo
3208 x_modulo,
3209 y_modulo;
3210
3211 /*
3212 Transfer a single pixel.
3213 */
3214 length=(MagickSizeType) 1;
3215 switch (virtual_pixel_method)
3216 {
cristy3ed852e2009-09-05 21:47:34 +00003217 default:
3218 {
3219 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003220 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003221 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003222 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003223 break;
3224 }
3225 case RandomVirtualPixelMethod:
3226 {
3227 if (cache_info->random_info == (RandomInfo *) NULL)
3228 cache_info->random_info=AcquireRandomInfo();
3229 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003230 RandomX(cache_info->random_info,cache_info->columns),
3231 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003232 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003233 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003234 break;
3235 }
3236 case DitherVirtualPixelMethod:
3237 {
3238 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003239 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003240 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003241 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003242 break;
3243 }
3244 case TileVirtualPixelMethod:
3245 {
3246 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3247 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3248 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003249 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003250 exception);
cristy4c08aed2011-07-01 19:47:50 +00003251 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003252 break;
3253 }
3254 case MirrorVirtualPixelMethod:
3255 {
3256 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3257 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003258 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003259 x_modulo.remainder-1L;
3260 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3261 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003262 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003263 y_modulo.remainder-1L;
3264 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003265 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003266 exception);
cristy4c08aed2011-07-01 19:47:50 +00003267 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003268 break;
3269 }
3270 case HorizontalTileEdgeVirtualPixelMethod:
3271 {
3272 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3273 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003274 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003275 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003276 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003277 break;
3278 }
3279 case VerticalTileEdgeVirtualPixelMethod:
3280 {
3281 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3282 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003283 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003284 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003285 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3286 break;
3287 }
3288 case BackgroundVirtualPixelMethod:
3289 case BlackVirtualPixelMethod:
3290 case GrayVirtualPixelMethod:
3291 case TransparentVirtualPixelMethod:
3292 case MaskVirtualPixelMethod:
3293 case WhiteVirtualPixelMethod:
3294 {
3295 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003296 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003297 break;
3298 }
3299 case EdgeVirtualPixelMethod:
3300 case CheckerTileVirtualPixelMethod:
3301 {
3302 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3303 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3304 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3305 {
3306 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003307 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003308 break;
3309 }
3310 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3311 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3312 exception);
3313 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3314 break;
3315 }
3316 case HorizontalTileVirtualPixelMethod:
3317 {
3318 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3319 {
3320 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003321 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003322 break;
3323 }
3324 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3325 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3326 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3327 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3328 exception);
3329 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3330 break;
3331 }
3332 case VerticalTileVirtualPixelMethod:
3333 {
3334 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3335 {
3336 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003337 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003338 break;
3339 }
3340 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3341 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3342 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3343 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3344 exception);
3345 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003346 break;
3347 }
3348 }
cristy4c08aed2011-07-01 19:47:50 +00003349 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003350 break;
cristyed231572011-07-14 02:18:59 +00003351 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003352 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003353 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003354 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003355 {
3356 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3357 s+=cache_info->metacontent_extent;
3358 }
cristy3ed852e2009-09-05 21:47:34 +00003359 continue;
3360 }
3361 /*
3362 Transfer a run of pixels.
3363 */
cristy4c08aed2011-07-01 19:47:50 +00003364 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3365 length,1UL,*virtual_nexus,exception);
3366 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003367 break;
cristy4c08aed2011-07-01 19:47:50 +00003368 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003369 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3370 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003371 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003372 {
cristy4c08aed2011-07-01 19:47:50 +00003373 (void) memcpy(s,r,(size_t) length);
3374 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003375 }
3376 }
3377 }
cristy4c08aed2011-07-01 19:47:50 +00003378 /*
3379 Free resources.
3380 */
cristy105ba3c2011-07-18 02:28:38 +00003381 if (virtual_metacontent != (void *) NULL)
3382 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003383 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3384 return(pixels);
3385}
3386
3387/*
3388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3389% %
3390% %
3391% %
3392+ G e t V i r t u a l P i x e l C a c h e %
3393% %
3394% %
3395% %
3396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3397%
3398% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3399% cache as defined by the geometry parameters. A pointer to the pixels
3400% is returned if the pixels are transferred, otherwise a NULL is returned.
3401%
3402% The format of the GetVirtualPixelCache() method is:
3403%
cristy4c08aed2011-07-01 19:47:50 +00003404% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003405% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3406% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003407% ExceptionInfo *exception)
3408%
3409% A description of each parameter follows:
3410%
3411% o image: the image.
3412%
3413% o virtual_pixel_method: the virtual pixel method.
3414%
3415% o x,y,columns,rows: These values define the perimeter of a region of
3416% pixels.
3417%
3418% o exception: return any errors or warnings in this structure.
3419%
3420*/
cristy4c08aed2011-07-01 19:47:50 +00003421static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003422 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3423 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003424{
3425 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003426 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003427
cristy5c9e6f22010-09-17 17:31:01 +00003428 const int
3429 id = GetOpenMPThreadId();
3430
cristy4c08aed2011-07-01 19:47:50 +00003431 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003432 *p;
cristy4c08aed2011-07-01 19:47:50 +00003433
cristye7cc7cf2010-09-21 13:26:47 +00003434 assert(image != (const Image *) NULL);
3435 assert(image->signature == MagickSignature);
3436 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003437 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003438 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003439 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003440 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003441 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003442 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003443}
3444
3445/*
3446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3447% %
3448% %
3449% %
3450% G e t V i r t u a l P i x e l Q u e u e %
3451% %
3452% %
3453% %
3454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3455%
cristy4c08aed2011-07-01 19:47:50 +00003456% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3457% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003458%
3459% The format of the GetVirtualPixelQueue() method is:
3460%
cristy4c08aed2011-07-01 19:47:50 +00003461% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003462%
3463% A description of each parameter follows:
3464%
3465% o image: the image.
3466%
3467*/
cristy4c08aed2011-07-01 19:47:50 +00003468MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003469{
3470 CacheInfo
3471 *cache_info;
3472
cristy2036f5c2010-09-19 21:18:17 +00003473 const int
3474 id = GetOpenMPThreadId();
3475
cristy3ed852e2009-09-05 21:47:34 +00003476 assert(image != (const Image *) NULL);
3477 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003478 assert(image->cache != (Cache) NULL);
3479 cache_info=(CacheInfo *) image->cache;
3480 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003481 if (cache_info->methods.get_virtual_pixels_handler !=
3482 (GetVirtualPixelsHandler) NULL)
3483 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003484 assert(id < (int) cache_info->number_threads);
3485 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003486}
3487
3488/*
3489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3490% %
3491% %
3492% %
3493% G e t V i r t u a l P i x e l s %
3494% %
3495% %
3496% %
3497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3498%
3499% GetVirtualPixels() returns an immutable pixel region. If the
3500% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003501% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003502% copy of the pixels or it may point to the original pixels in memory.
3503% Performance is maximized if the selected region is part of one row, or one
3504% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003505% (without a copy) if the image is in memory, or in a memory-mapped file. The
3506% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003507%
3508% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003509% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3510% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3511% access the meta-content (of type void) corresponding to the the
3512% region.
cristy3ed852e2009-09-05 21:47:34 +00003513%
3514% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3515%
3516% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3517% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3518% GetCacheViewAuthenticPixels() instead.
3519%
3520% The format of the GetVirtualPixels() method is:
3521%
cristy4c08aed2011-07-01 19:47:50 +00003522% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003523% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003524% ExceptionInfo *exception)
3525%
3526% A description of each parameter follows:
3527%
3528% o image: the image.
3529%
3530% o x,y,columns,rows: These values define the perimeter of a region of
3531% pixels.
3532%
3533% o exception: return any errors or warnings in this structure.
3534%
3535*/
cristy4c08aed2011-07-01 19:47:50 +00003536MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003537 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3538 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003539{
3540 CacheInfo
3541 *cache_info;
3542
cristy2036f5c2010-09-19 21:18:17 +00003543 const int
3544 id = GetOpenMPThreadId();
3545
cristy4c08aed2011-07-01 19:47:50 +00003546 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003547 *p;
cristy4c08aed2011-07-01 19:47:50 +00003548
cristy3ed852e2009-09-05 21:47:34 +00003549 assert(image != (const Image *) NULL);
3550 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003551 assert(image->cache != (Cache) NULL);
3552 cache_info=(CacheInfo *) image->cache;
3553 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003554 if (cache_info->methods.get_virtual_pixel_handler !=
3555 (GetVirtualPixelHandler) NULL)
3556 return(cache_info->methods.get_virtual_pixel_handler(image,
3557 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003558 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003559 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003560 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003561 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003562}
3563
3564/*
3565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3566% %
3567% %
3568% %
3569+ 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 %
3570% %
3571% %
3572% %
3573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3574%
cristy4c08aed2011-07-01 19:47:50 +00003575% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3576% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003577%
3578% The format of the GetVirtualPixelsCache() method is:
3579%
cristy4c08aed2011-07-01 19:47:50 +00003580% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003581%
3582% A description of each parameter follows:
3583%
3584% o image: the image.
3585%
3586*/
cristy4c08aed2011-07-01 19:47:50 +00003587static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003588{
3589 CacheInfo
3590 *cache_info;
3591
cristy5c9e6f22010-09-17 17:31:01 +00003592 const int
3593 id = GetOpenMPThreadId();
3594
cristye7cc7cf2010-09-21 13:26:47 +00003595 assert(image != (const Image *) NULL);
3596 assert(image->signature == MagickSignature);
3597 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003598 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003599 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003600 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003601 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003602}
3603
3604/*
3605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3606% %
3607% %
3608% %
3609+ G e t V i r t u a l P i x e l s N e x u s %
3610% %
3611% %
3612% %
3613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614%
3615% GetVirtualPixelsNexus() returns the pixels associated with the specified
3616% cache nexus.
3617%
3618% The format of the GetVirtualPixelsNexus() method is:
3619%
cristy4c08aed2011-07-01 19:47:50 +00003620% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003621% NexusInfo *nexus_info)
3622%
3623% A description of each parameter follows:
3624%
3625% o cache: the pixel cache.
3626%
3627% o nexus_info: the cache nexus to return the colormap pixels.
3628%
3629*/
cristya6577ff2011-09-02 19:54:26 +00003630MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003631 NexusInfo *nexus_info)
3632{
3633 CacheInfo
3634 *cache_info;
3635
cristye7cc7cf2010-09-21 13:26:47 +00003636 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003637 cache_info=(CacheInfo *) cache;
3638 assert(cache_info->signature == MagickSignature);
3639 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003640 return((Quantum *) NULL);
3641 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003642}
3643
3644/*
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646% %
3647% %
3648% %
cristy3ed852e2009-09-05 21:47:34 +00003649+ O p e n P i x e l C a c h e %
3650% %
3651% %
3652% %
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654%
3655% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3656% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003657% metacontent, and memory mapping the cache if it is disk based. The cache
3658% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003659%
3660% The format of the OpenPixelCache() method is:
3661%
3662% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3663% ExceptionInfo *exception)
3664%
3665% A description of each parameter follows:
3666%
3667% o image: the image.
3668%
3669% o mode: ReadMode, WriteMode, or IOMode.
3670%
3671% o exception: return any errors or warnings in this structure.
3672%
3673*/
3674
cristyd43a46b2010-01-21 02:13:41 +00003675static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003676{
3677 cache_info->mapped=MagickFalse;
cristye42639a2012-08-23 01:53:24 +00003678 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3679 (size_t) cache_info->length));
cristy4c08aed2011-07-01 19:47:50 +00003680 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003681 {
3682 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003683 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003684 cache_info->length);
3685 }
3686}
3687
3688static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3689{
3690 CacheInfo
3691 *cache_info;
3692
3693 MagickOffsetType
cristy3ed852e2009-09-05 21:47:34 +00003694 extent,
3695 offset;
3696
3697 cache_info=(CacheInfo *) image->cache;
3698 if (image->debug != MagickFalse)
3699 {
3700 char
3701 format[MaxTextExtent],
3702 message[MaxTextExtent];
3703
cristyb9080c92009-12-01 20:13:26 +00003704 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003705 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003706 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003707 cache_info->cache_filename,cache_info->file,format);
3708 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3709 }
3710 if (length != (MagickSizeType) ((MagickOffsetType) length))
3711 return(MagickFalse);
cristy911f2b12012-10-18 14:55:28 +00003712 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3713 if (offset < 0)
cristy3ed852e2009-09-05 21:47:34 +00003714 return(MagickFalse);
cristy911f2b12012-10-18 14:55:28 +00003715 if ((MagickSizeType) offset >= length)
cristy3ed852e2009-09-05 21:47:34 +00003716 return(MagickTrue);
cristy911f2b12012-10-18 14:55:28 +00003717 extent=(MagickOffsetType) length-1;
cristy3b5a2cf2012-10-18 14:50:08 +00003718#if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3719 {
3720 MagickOffsetType
3721 count;
3722
cristy911f2b12012-10-18 14:55:28 +00003723 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
cristy3b5a2cf2012-10-18 14:50:08 +00003724 if (count != (MagickOffsetType) 1)
3725 return(MagickFalse);
3726 }
3727#else
3728 {
3729 int
3730 status;
3731
cristy911f2b12012-10-18 14:55:28 +00003732 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
cristy3b5a2cf2012-10-18 14:50:08 +00003733 if (status != 0)
3734 return(MagickFalse);
3735 }
3736#endif
3737 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003738}
3739
3740static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3741 ExceptionInfo *exception)
3742{
cristy3ed852e2009-09-05 21:47:34 +00003743 CacheInfo
3744 *cache_info,
3745 source_info;
3746
cristyf3a6a9d2010-11-07 21:02:56 +00003747 char
3748 format[MaxTextExtent],
3749 message[MaxTextExtent];
3750
cristy4c08aed2011-07-01 19:47:50 +00003751 MagickBooleanType
3752 status;
3753
cristy3ed852e2009-09-05 21:47:34 +00003754 MagickSizeType
3755 length,
3756 number_pixels;
3757
cristy3ed852e2009-09-05 21:47:34 +00003758 size_t
cristye076a6e2010-08-15 19:59:43 +00003759 columns,
cristy3ed852e2009-09-05 21:47:34 +00003760 packet_size;
3761
cristye7cc7cf2010-09-21 13:26:47 +00003762 assert(image != (const Image *) NULL);
3763 assert(image->signature == MagickSignature);
3764 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003765 if (image->debug != MagickFalse)
3766 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3767 if ((image->columns == 0) || (image->rows == 0))
3768 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3769 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003770 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003771 source_info=(*cache_info);
3772 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003773 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003774 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003775 cache_info->storage_class=image->storage_class;
3776 cache_info->colorspace=image->colorspace;
cristy8a46d822012-08-28 23:32:39 +00003777 cache_info->alpha_trait=image->alpha_trait;
cristy183a5c72012-01-30 01:40:35 +00003778 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003779 cache_info->rows=image->rows;
3780 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003781 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003782 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003783 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3784 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003785 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003786 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003787 if (image->ping != MagickFalse)
3788 {
cristy73724512010-04-12 14:43:14 +00003789 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003790 cache_info->pixels=(Quantum *) NULL;
3791 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003792 cache_info->length=0;
3793 return(MagickTrue);
3794 }
cristy3ed852e2009-09-05 21:47:34 +00003795 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003796 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003797 if (image->metacontent_extent != 0)
3798 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003799 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003800 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003801 if (cache_info->columns != columns)
3802 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3803 image->filename);
3804 cache_info->length=length;
3805 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003806 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003807 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003808 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3809 {
3810 status=AcquireMagickResource(MemoryResource,cache_info->length);
3811 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3812 (cache_info->type == MemoryCache))
3813 {
cristyd43a46b2010-01-21 02:13:41 +00003814 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003815 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003816 cache_info->pixels=source_info.pixels;
3817 else
3818 {
3819 /*
3820 Create memory pixel cache.
3821 */
cristy4c08aed2011-07-01 19:47:50 +00003822 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003823 if (image->debug != MagickFalse)
3824 {
cristy32cacff2011-12-31 03:36:27 +00003825 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003826 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003827 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3828 cache_info->filename,cache_info->mapped != MagickFalse ?
3829 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003830 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003831 format);
cristy3ed852e2009-09-05 21:47:34 +00003832 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3833 message);
3834 }
cristy3ed852e2009-09-05 21:47:34 +00003835 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003836 cache_info->metacontent=(void *) NULL;
3837 if (cache_info->metacontent_extent != 0)
3838 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003839 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003840 if ((source_info.storage_class != UndefinedClass) &&
3841 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003842 {
cristy4c08aed2011-07-01 19:47:50 +00003843 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003844 exception);
3845 RelinquishPixelCachePixels(&source_info);
3846 }
cristy4c08aed2011-07-01 19:47:50 +00003847 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003848 }
3849 }
3850 RelinquishMagickResource(MemoryResource,cache_info->length);
3851 }
3852 /*
3853 Create pixel cache on disk.
3854 */
3855 status=AcquireMagickResource(DiskResource,cache_info->length);
3856 if (status == MagickFalse)
3857 {
3858 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003859 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003860 return(MagickFalse);
3861 }
cristy413f1302012-01-01 17:48:27 +00003862 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3863 {
3864 (void) ClosePixelCacheOnDisk(cache_info);
3865 *cache_info->cache_filename='\0';
3866 }
cristy3ed852e2009-09-05 21:47:34 +00003867 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3868 {
3869 RelinquishMagickResource(DiskResource,cache_info->length);
3870 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3871 image->filename);
3872 return(MagickFalse);
3873 }
3874 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3875 cache_info->length);
3876 if (status == MagickFalse)
3877 {
3878 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3879 image->filename);
3880 return(MagickFalse);
3881 }
cristyed231572011-07-14 02:18:59 +00003882 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003883 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003884 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003885 cache_info->type=DiskCache;
3886 else
3887 {
3888 status=AcquireMagickResource(MapResource,cache_info->length);
3889 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3890 (cache_info->type != MemoryCache))
3891 cache_info->type=DiskCache;
3892 else
3893 {
cristy4c08aed2011-07-01 19:47:50 +00003894 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003895 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003896 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003897 {
cristy3ed852e2009-09-05 21:47:34 +00003898 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003899 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003900 }
3901 else
3902 {
3903 /*
3904 Create file-backed memory-mapped pixel cache.
3905 */
cristy4c08aed2011-07-01 19:47:50 +00003906 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003907 (void) ClosePixelCacheOnDisk(cache_info);
3908 cache_info->type=MapCache;
3909 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003910 cache_info->metacontent=(void *) NULL;
3911 if (cache_info->metacontent_extent != 0)
3912 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003913 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003914 if ((source_info.storage_class != UndefinedClass) &&
3915 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003916 {
3917 status=ClonePixelCachePixels(cache_info,&source_info,
3918 exception);
3919 RelinquishPixelCachePixels(&source_info);
3920 }
3921 if (image->debug != MagickFalse)
3922 {
cristy413f1302012-01-01 17:48:27 +00003923 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003924 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003925 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003926 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003927 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003928 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003929 format);
cristy3ed852e2009-09-05 21:47:34 +00003930 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3931 message);
3932 }
cristy4c08aed2011-07-01 19:47:50 +00003933 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003934 }
3935 }
3936 RelinquishMagickResource(MapResource,cache_info->length);
3937 }
cristy4c08aed2011-07-01 19:47:50 +00003938 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003939 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003940 {
3941 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3942 RelinquishPixelCachePixels(&source_info);
3943 }
3944 if (image->debug != MagickFalse)
3945 {
cristyb9080c92009-12-01 20:13:26 +00003946 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003947 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003948 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003949 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003950 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003951 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003952 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3953 }
cristy4c08aed2011-07-01 19:47:50 +00003954 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003955}
3956
3957/*
3958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3959% %
3960% %
3961% %
3962+ P e r s i s t P i x e l C a c h e %
3963% %
3964% %
3965% %
3966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3967%
3968% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3969% persistent pixel cache is one that resides on disk and is not destroyed
3970% when the program exits.
3971%
3972% The format of the PersistPixelCache() method is:
3973%
3974% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3975% const MagickBooleanType attach,MagickOffsetType *offset,
3976% ExceptionInfo *exception)
3977%
3978% A description of each parameter follows:
3979%
3980% o image: the image.
3981%
3982% o filename: the persistent pixel cache filename.
3983%
cristyf3a6a9d2010-11-07 21:02:56 +00003984% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003985%
cristy3ed852e2009-09-05 21:47:34 +00003986% o initialize: A value other than zero initializes the persistent pixel
3987% cache.
3988%
3989% o offset: the offset in the persistent cache to store pixels.
3990%
3991% o exception: return any errors or warnings in this structure.
3992%
3993*/
3994MagickExport MagickBooleanType PersistPixelCache(Image *image,
3995 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3996 ExceptionInfo *exception)
3997{
3998 CacheInfo
3999 *cache_info,
4000 *clone_info;
4001
4002 Image
4003 clone_image;
4004
cristy3ed852e2009-09-05 21:47:34 +00004005 MagickBooleanType
4006 status;
4007
cristye076a6e2010-08-15 19:59:43 +00004008 ssize_t
4009 page_size;
4010
cristy3ed852e2009-09-05 21:47:34 +00004011 assert(image != (Image *) NULL);
4012 assert(image->signature == MagickSignature);
4013 if (image->debug != MagickFalse)
4014 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4015 assert(image->cache != (void *) NULL);
4016 assert(filename != (const char *) NULL);
4017 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004018 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004019 cache_info=(CacheInfo *) image->cache;
4020 assert(cache_info->signature == MagickSignature);
4021 if (attach != MagickFalse)
4022 {
4023 /*
cristy01b7eb02009-09-10 23:10:14 +00004024 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004025 */
4026 if (image->debug != MagickFalse)
4027 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004028 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004029 (void) CopyMagickString(cache_info->cache_filename,filename,
4030 MaxTextExtent);
4031 cache_info->type=DiskCache;
4032 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004033 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004034 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004035 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004036 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004037 }
cristy01b7eb02009-09-10 23:10:14 +00004038 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4039 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004040 {
cristyf84a1932010-01-03 18:00:18 +00004041 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004042 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004043 (cache_info->reference_count == 1))
4044 {
4045 int
4046 status;
4047
4048 /*
cristy01b7eb02009-09-10 23:10:14 +00004049 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004050 */
cristy320684d2011-09-23 14:55:47 +00004051 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004052 if (status == 0)
4053 {
4054 (void) CopyMagickString(cache_info->cache_filename,filename,
4055 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004056 *offset+=cache_info->length+page_size-(cache_info->length %
4057 page_size);
cristyf84a1932010-01-03 18:00:18 +00004058 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004059 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004060 if (image->debug != MagickFalse)
4061 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4062 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004063 return(MagickTrue);
4064 }
4065 }
cristyf84a1932010-01-03 18:00:18 +00004066 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004067 }
4068 /*
cristy01b7eb02009-09-10 23:10:14 +00004069 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004070 */
4071 clone_image=(*image);
4072 clone_info=(CacheInfo *) clone_image.cache;
4073 image->cache=ClonePixelCache(cache_info);
4074 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4075 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4076 cache_info->type=DiskCache;
4077 cache_info->offset=(*offset);
4078 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004079 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004080 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004081 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004082 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004083 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4084 return(status);
4085}
4086
4087/*
4088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4089% %
4090% %
4091% %
cristyc11dace2012-01-24 16:39:46 +00004092+ 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 +00004093% %
4094% %
4095% %
4096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4097%
cristyc11dace2012-01-24 16:39:46 +00004098% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4099% defined by the region rectangle and returns a pointer to the region. This
4100% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004101% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4102% pixels are transferred, otherwise a NULL is returned.
4103%
cristyc11dace2012-01-24 16:39:46 +00004104% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004105%
cristyc11dace2012-01-24 16:39:46 +00004106% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004107% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004108% const MagickBooleanType clone,NexusInfo *nexus_info,
4109% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004110%
4111% A description of each parameter follows:
4112%
4113% o image: the image.
4114%
4115% o x,y,columns,rows: These values define the perimeter of a region of
4116% pixels.
4117%
4118% o nexus_info: the cache nexus to set.
4119%
cristy65dbf172011-10-06 17:32:04 +00004120% o clone: clone the pixel cache.
4121%
cristy3ed852e2009-09-05 21:47:34 +00004122% o exception: return any errors or warnings in this structure.
4123%
4124*/
cristyc11dace2012-01-24 16:39:46 +00004125MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4126 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004127 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004128{
4129 CacheInfo
4130 *cache_info;
4131
4132 MagickOffsetType
4133 offset;
4134
4135 MagickSizeType
4136 number_pixels;
4137
4138 RectangleInfo
4139 region;
4140
4141 /*
4142 Validate pixel cache geometry.
4143 */
cristye7cc7cf2010-09-21 13:26:47 +00004144 assert(image != (const Image *) NULL);
4145 assert(image->signature == MagickSignature);
4146 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004147 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004148 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004149 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004150 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004151 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4152 {
4153 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004154 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004155 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004156 }
cristybb503372010-05-27 20:51:26 +00004157 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4158 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004159 {
4160 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004161 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004162 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004163 }
4164 offset=(MagickOffsetType) y*cache_info->columns+x;
4165 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004166 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004167 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4168 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4169 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004170 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004171 /*
4172 Return pixel cache.
4173 */
4174 region.x=x;
4175 region.y=y;
4176 region.width=columns;
4177 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004178 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004179}
4180
4181/*
4182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4183% %
4184% %
4185% %
4186+ 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 %
4187% %
4188% %
4189% %
4190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4191%
4192% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4193% defined by the region rectangle and returns a pointer to the region. This
4194% region is subsequently transferred from the pixel cache with
4195% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4196% pixels are transferred, otherwise a NULL is returned.
4197%
4198% The format of the QueueAuthenticPixelsCache() method is:
4199%
cristy4c08aed2011-07-01 19:47:50 +00004200% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004201% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004202% ExceptionInfo *exception)
4203%
4204% A description of each parameter follows:
4205%
4206% o image: the image.
4207%
4208% o x,y,columns,rows: These values define the perimeter of a region of
4209% pixels.
4210%
4211% o exception: return any errors or warnings in this structure.
4212%
4213*/
cristy4c08aed2011-07-01 19:47:50 +00004214static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004215 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004216 ExceptionInfo *exception)
4217{
4218 CacheInfo
4219 *cache_info;
4220
cristy5c9e6f22010-09-17 17:31:01 +00004221 const int
4222 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004223
cristy4c08aed2011-07-01 19:47:50 +00004224 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004225 *q;
cristy4c08aed2011-07-01 19:47:50 +00004226
cristye7cc7cf2010-09-21 13:26:47 +00004227 assert(image != (const Image *) NULL);
4228 assert(image->signature == MagickSignature);
4229 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004230 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004231 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004232 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004233 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004234 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004235 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004236}
4237
4238/*
4239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4240% %
4241% %
4242% %
4243% Q u e u e A u t h e n t i c P i x e l s %
4244% %
4245% %
4246% %
4247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4248%
4249% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004250% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004251% region is returned, otherwise NULL is returned. The returned pointer may
4252% point to a temporary working buffer for the pixels or it may point to the
4253% final location of the pixels in memory.
4254%
4255% Write-only access means that any existing pixel values corresponding to
4256% the region are ignored. This is useful if the initial image is being
4257% created from scratch, or if the existing pixel values are to be
4258% completely replaced without need to refer to their pre-existing values.
4259% The application is free to read and write the pixel buffer returned by
4260% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4261% initialize the pixel array values. Initializing pixel array values is the
4262% application's responsibility.
4263%
4264% Performance is maximized if the selected region is part of one row, or
4265% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004266% pixels in-place (without a copy) if the image is in memory, or in a
4267% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004268% by the user.
4269%
4270% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004271% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4272% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4273% obtain the meta-content (of type void) corresponding to the region.
4274% Once the Quantum (and/or Quantum) array has been updated, the
4275% changes must be saved back to the underlying image using
4276% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004277%
4278% The format of the QueueAuthenticPixels() method is:
4279%
cristy4c08aed2011-07-01 19:47:50 +00004280% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004281% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004282% ExceptionInfo *exception)
4283%
4284% A description of each parameter follows:
4285%
4286% o image: the image.
4287%
4288% o x,y,columns,rows: These values define the perimeter of a region of
4289% pixels.
4290%
4291% o exception: return any errors or warnings in this structure.
4292%
4293*/
cristy4c08aed2011-07-01 19:47:50 +00004294MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004295 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004296 ExceptionInfo *exception)
4297{
4298 CacheInfo
4299 *cache_info;
4300
cristy2036f5c2010-09-19 21:18:17 +00004301 const int
4302 id = GetOpenMPThreadId();
4303
cristy4c08aed2011-07-01 19:47:50 +00004304 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004305 *q;
cristy4c08aed2011-07-01 19:47:50 +00004306
cristy3ed852e2009-09-05 21:47:34 +00004307 assert(image != (Image *) NULL);
4308 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004309 assert(image->cache != (Cache) NULL);
4310 cache_info=(CacheInfo *) image->cache;
4311 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004312 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004313 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004314 {
cristyc36c8822012-02-14 14:02:36 +00004315 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4316 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004317 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004318 }
cristy2036f5c2010-09-19 21:18:17 +00004319 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004320 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004321 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004322 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004323}
4324
4325/*
4326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4327% %
4328% %
4329% %
cristy4c08aed2011-07-01 19:47:50 +00004330+ 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 +00004331% %
4332% %
4333% %
4334%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4335%
cristy4c08aed2011-07-01 19:47:50 +00004336% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004337% the pixel cache.
4338%
cristy4c08aed2011-07-01 19:47:50 +00004339% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004340%
cristy4c08aed2011-07-01 19:47:50 +00004341% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004342% NexusInfo *nexus_info,ExceptionInfo *exception)
4343%
4344% A description of each parameter follows:
4345%
4346% o cache_info: the pixel cache.
4347%
cristy4c08aed2011-07-01 19:47:50 +00004348% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004349%
4350% o exception: return any errors or warnings in this structure.
4351%
4352*/
cristy4c08aed2011-07-01 19:47:50 +00004353static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004354 NexusInfo *nexus_info,ExceptionInfo *exception)
4355{
4356 MagickOffsetType
4357 count,
4358 offset;
4359
4360 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004361 extent,
4362 length;
cristy3ed852e2009-09-05 21:47:34 +00004363
cristybb503372010-05-27 20:51:26 +00004364 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004365 y;
4366
cristy4c08aed2011-07-01 19:47:50 +00004367 register unsigned char
4368 *restrict q;
4369
cristybb503372010-05-27 20:51:26 +00004370 size_t
cristy3ed852e2009-09-05 21:47:34 +00004371 rows;
4372
cristy4c08aed2011-07-01 19:47:50 +00004373 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004374 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004375 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004376 return(MagickTrue);
4377 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4378 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004379 length=(MagickSizeType) nexus_info->region.width*
4380 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004381 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004382 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004383 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004384 switch (cache_info->type)
4385 {
4386 case MemoryCache:
4387 case MapCache:
4388 {
cristy4c08aed2011-07-01 19:47:50 +00004389 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004390 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004391
4392 /*
cristy4c08aed2011-07-01 19:47:50 +00004393 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004394 */
cristydd341db2010-03-04 19:06:38 +00004395 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004396 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004397 {
cristy48078b12010-09-23 17:11:01 +00004398 length=extent;
cristydd341db2010-03-04 19:06:38 +00004399 rows=1UL;
4400 }
cristy4c08aed2011-07-01 19:47:50 +00004401 p=(unsigned char *) cache_info->metacontent+offset*
4402 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004403 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004404 {
cristy8f036fe2010-09-18 02:02:00 +00004405 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004406 p+=cache_info->metacontent_extent*cache_info->columns;
4407 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004408 }
4409 break;
4410 }
4411 case DiskCache:
4412 {
4413 /*
cristy4c08aed2011-07-01 19:47:50 +00004414 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004415 */
4416 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4417 {
4418 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4419 cache_info->cache_filename);
4420 return(MagickFalse);
4421 }
cristydd341db2010-03-04 19:06:38 +00004422 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004423 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004424 {
cristy48078b12010-09-23 17:11:01 +00004425 length=extent;
cristydd341db2010-03-04 19:06:38 +00004426 rows=1UL;
4427 }
cristy48078b12010-09-23 17:11:01 +00004428 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004429 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004430 {
cristy48078b12010-09-23 17:11:01 +00004431 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004432 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004433 cache_info->metacontent_extent,length,(unsigned char *) q);
4434 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004435 break;
4436 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004437 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004438 }
cristyc11dace2012-01-24 16:39:46 +00004439 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4440 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004441 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004442 {
4443 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4444 cache_info->cache_filename);
4445 return(MagickFalse);
4446 }
4447 break;
4448 }
4449 default:
4450 break;
4451 }
4452 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004453 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004454 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004455 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004456 nexus_info->region.width,(double) nexus_info->region.height,(double)
4457 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004458 return(MagickTrue);
4459}
4460
4461/*
4462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4463% %
4464% %
4465% %
4466+ R e a d P i x e l C a c h e P i x e l s %
4467% %
4468% %
4469% %
4470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4471%
4472% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4473% cache.
4474%
4475% The format of the ReadPixelCachePixels() method is:
4476%
4477% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4478% NexusInfo *nexus_info,ExceptionInfo *exception)
4479%
4480% A description of each parameter follows:
4481%
4482% o cache_info: the pixel cache.
4483%
4484% o nexus_info: the cache nexus to read the pixels.
4485%
4486% o exception: return any errors or warnings in this structure.
4487%
4488*/
4489static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4490 NexusInfo *nexus_info,ExceptionInfo *exception)
4491{
4492 MagickOffsetType
4493 count,
4494 offset;
4495
4496 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004497 extent,
4498 length;
cristy3ed852e2009-09-05 21:47:34 +00004499
cristy4c08aed2011-07-01 19:47:50 +00004500 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004501 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004502
cristye076a6e2010-08-15 19:59:43 +00004503 register ssize_t
4504 y;
4505
cristybb503372010-05-27 20:51:26 +00004506 size_t
cristy3ed852e2009-09-05 21:47:34 +00004507 rows;
4508
cristy4c08aed2011-07-01 19:47:50 +00004509 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004510 return(MagickTrue);
4511 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4512 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004513 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004514 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004515 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004516 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004517 q=nexus_info->pixels;
4518 switch (cache_info->type)
4519 {
4520 case MemoryCache:
4521 case MapCache:
4522 {
cristy4c08aed2011-07-01 19:47:50 +00004523 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004524 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004525
4526 /*
4527 Read pixels from memory.
4528 */
cristydd341db2010-03-04 19:06:38 +00004529 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004530 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004531 {
cristy48078b12010-09-23 17:11:01 +00004532 length=extent;
cristydd341db2010-03-04 19:06:38 +00004533 rows=1UL;
4534 }
cristyed231572011-07-14 02:18:59 +00004535 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004536 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004537 {
cristy8f036fe2010-09-18 02:02:00 +00004538 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004539 p+=cache_info->number_channels*cache_info->columns;
4540 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004541 }
4542 break;
4543 }
4544 case DiskCache:
4545 {
4546 /*
4547 Read pixels from disk.
4548 */
4549 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4550 {
4551 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4552 cache_info->cache_filename);
4553 return(MagickFalse);
4554 }
cristydd341db2010-03-04 19:06:38 +00004555 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004556 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004557 {
cristy48078b12010-09-23 17:11:01 +00004558 length=extent;
cristydd341db2010-03-04 19:06:38 +00004559 rows=1UL;
4560 }
cristybb503372010-05-27 20:51:26 +00004561 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004562 {
4563 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004564 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004565 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004566 break;
4567 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004568 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004569 }
cristyc11dace2012-01-24 16:39:46 +00004570 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4571 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004572 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004573 {
4574 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4575 cache_info->cache_filename);
4576 return(MagickFalse);
4577 }
4578 break;
4579 }
4580 default:
4581 break;
4582 }
4583 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004584 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004585 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004586 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004587 nexus_info->region.width,(double) nexus_info->region.height,(double)
4588 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004589 return(MagickTrue);
4590}
4591
4592/*
4593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4594% %
4595% %
4596% %
4597+ R e f e r e n c e P i x e l C a c h e %
4598% %
4599% %
4600% %
4601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4602%
4603% ReferencePixelCache() increments the reference count associated with the
4604% pixel cache returning a pointer to the cache.
4605%
4606% The format of the ReferencePixelCache method is:
4607%
4608% Cache ReferencePixelCache(Cache cache_info)
4609%
4610% A description of each parameter follows:
4611%
4612% o cache_info: the pixel cache.
4613%
4614*/
cristya6577ff2011-09-02 19:54:26 +00004615MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004616{
4617 CacheInfo
4618 *cache_info;
4619
4620 assert(cache != (Cache *) NULL);
4621 cache_info=(CacheInfo *) cache;
4622 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004623 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004624 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004625 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004626 return(cache_info);
4627}
4628
4629/*
4630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4631% %
4632% %
4633% %
4634+ S e t P i x e l C a c h e M e t h o d s %
4635% %
4636% %
4637% %
4638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4639%
4640% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4641%
4642% The format of the SetPixelCacheMethods() method is:
4643%
4644% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4645%
4646% A description of each parameter follows:
4647%
4648% o cache: the pixel cache.
4649%
4650% o cache_methods: Specifies a pointer to a CacheMethods structure.
4651%
4652*/
cristya6577ff2011-09-02 19:54:26 +00004653MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004654{
4655 CacheInfo
4656 *cache_info;
4657
4658 GetOneAuthenticPixelFromHandler
4659 get_one_authentic_pixel_from_handler;
4660
4661 GetOneVirtualPixelFromHandler
4662 get_one_virtual_pixel_from_handler;
4663
4664 /*
4665 Set cache pixel methods.
4666 */
4667 assert(cache != (Cache) NULL);
4668 assert(cache_methods != (CacheMethods *) NULL);
4669 cache_info=(CacheInfo *) cache;
4670 assert(cache_info->signature == MagickSignature);
4671 if (cache_info->debug != MagickFalse)
4672 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4673 cache_info->filename);
4674 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4675 cache_info->methods.get_virtual_pixel_handler=
4676 cache_methods->get_virtual_pixel_handler;
4677 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4678 cache_info->methods.destroy_pixel_handler=
4679 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004680 if (cache_methods->get_virtual_metacontent_from_handler !=
4681 (GetVirtualMetacontentFromHandler) NULL)
4682 cache_info->methods.get_virtual_metacontent_from_handler=
4683 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004684 if (cache_methods->get_authentic_pixels_handler !=
4685 (GetAuthenticPixelsHandler) NULL)
4686 cache_info->methods.get_authentic_pixels_handler=
4687 cache_methods->get_authentic_pixels_handler;
4688 if (cache_methods->queue_authentic_pixels_handler !=
4689 (QueueAuthenticPixelsHandler) NULL)
4690 cache_info->methods.queue_authentic_pixels_handler=
4691 cache_methods->queue_authentic_pixels_handler;
4692 if (cache_methods->sync_authentic_pixels_handler !=
4693 (SyncAuthenticPixelsHandler) NULL)
4694 cache_info->methods.sync_authentic_pixels_handler=
4695 cache_methods->sync_authentic_pixels_handler;
4696 if (cache_methods->get_authentic_pixels_from_handler !=
4697 (GetAuthenticPixelsFromHandler) NULL)
4698 cache_info->methods.get_authentic_pixels_from_handler=
4699 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004700 if (cache_methods->get_authentic_metacontent_from_handler !=
4701 (GetAuthenticMetacontentFromHandler) NULL)
4702 cache_info->methods.get_authentic_metacontent_from_handler=
4703 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004704 get_one_virtual_pixel_from_handler=
4705 cache_info->methods.get_one_virtual_pixel_from_handler;
4706 if (get_one_virtual_pixel_from_handler !=
4707 (GetOneVirtualPixelFromHandler) NULL)
4708 cache_info->methods.get_one_virtual_pixel_from_handler=
4709 cache_methods->get_one_virtual_pixel_from_handler;
4710 get_one_authentic_pixel_from_handler=
4711 cache_methods->get_one_authentic_pixel_from_handler;
4712 if (get_one_authentic_pixel_from_handler !=
4713 (GetOneAuthenticPixelFromHandler) NULL)
4714 cache_info->methods.get_one_authentic_pixel_from_handler=
4715 cache_methods->get_one_authentic_pixel_from_handler;
4716}
4717
4718/*
4719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4720% %
4721% %
4722% %
4723+ S e t P i x e l C a c h e N e x u s P i x e l s %
4724% %
4725% %
4726% %
4727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4728%
4729% SetPixelCacheNexusPixels() defines the region of the cache for the
4730% specified cache nexus.
4731%
4732% The format of the SetPixelCacheNexusPixels() method is:
4733%
cristy265a2b22012-05-11 12:48:50 +00004734% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004735% const RectangleInfo *region,NexusInfo *nexus_info,
4736% ExceptionInfo *exception)
4737%
4738% A description of each parameter follows:
4739%
4740% o image: the image.
4741%
cristy265a2b22012-05-11 12:48:50 +00004742% o mode: ReadMode, WriteMode, or IOMode.
4743%
cristy3ed852e2009-09-05 21:47:34 +00004744% o region: A pointer to the RectangleInfo structure that defines the
4745% region of this particular cache nexus.
4746%
4747% o nexus_info: the cache nexus to set.
4748%
4749% o exception: return any errors or warnings in this structure.
4750%
4751*/
cristyabd6e372010-09-15 19:11:26 +00004752
cristyf1832792012-05-08 18:38:18 +00004753static inline MagickBooleanType AcquireCacheNexusPixels(
4754 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4755 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004756{
4757 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4758 return(MagickFalse);
4759 nexus_info->mapped=MagickFalse;
cristye42639a2012-08-23 01:53:24 +00004760 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4761 (size_t) nexus_info->length));
cristy4c08aed2011-07-01 19:47:50 +00004762 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004763 {
4764 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004765 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004766 nexus_info->length);
4767 }
cristy4c08aed2011-07-01 19:47:50 +00004768 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004769 {
4770 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004771 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004772 cache_info->filename);
4773 return(MagickFalse);
4774 }
4775 return(MagickTrue);
4776}
4777
cristyadf82722012-05-11 17:34:16 +00004778static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4779 const MapMode mode)
4780{
cristyfc5845e2012-05-11 18:18:13 +00004781 if (mode == ReadMode)
4782 {
4783 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4784 return;
4785 }
4786 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004787}
4788
cristy265a2b22012-05-11 12:48:50 +00004789static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004790 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4791{
4792 CacheInfo
4793 *cache_info;
4794
4795 MagickBooleanType
4796 status;
4797
cristy3ed852e2009-09-05 21:47:34 +00004798 MagickSizeType
4799 length,
4800 number_pixels;
4801
cristy3ed852e2009-09-05 21:47:34 +00004802 cache_info=(CacheInfo *) image->cache;
4803 assert(cache_info->signature == MagickSignature);
4804 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004805 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004806 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004807 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004808 {
cristybb503372010-05-27 20:51:26 +00004809 ssize_t
cristybad067a2010-02-15 17:20:55 +00004810 x,
4811 y;
cristy3ed852e2009-09-05 21:47:34 +00004812
cristyeaedf062010-05-29 22:36:02 +00004813 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4814 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004815 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4816 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004817 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004818 ((nexus_info->region.width == cache_info->columns) ||
4819 ((nexus_info->region.width % cache_info->columns) == 0)))))
4820 {
4821 MagickOffsetType
4822 offset;
4823
4824 /*
4825 Pixels are accessed directly from memory.
4826 */
4827 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4828 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004829 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004830 offset;
4831 nexus_info->metacontent=(void *) NULL;
4832 if (cache_info->metacontent_extent != 0)
4833 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4834 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004835 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004836 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004837 }
4838 }
4839 /*
4840 Pixels are stored in a cache region until they are synced to the cache.
4841 */
4842 number_pixels=(MagickSizeType) nexus_info->region.width*
4843 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004844 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004845 if (cache_info->metacontent_extent != 0)
4846 length+=number_pixels*cache_info->metacontent_extent;
4847 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004848 {
4849 nexus_info->length=length;
4850 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4851 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004852 {
4853 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004854 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004855 }
cristy3ed852e2009-09-05 21:47:34 +00004856 }
4857 else
4858 if (nexus_info->length != length)
4859 {
4860 RelinquishCacheNexusPixels(nexus_info);
4861 nexus_info->length=length;
4862 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4863 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004864 {
4865 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004866 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004867 }
cristy3ed852e2009-09-05 21:47:34 +00004868 }
4869 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004870 nexus_info->metacontent=(void *) NULL;
4871 if (cache_info->metacontent_extent != 0)
4872 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004873 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004874 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004875 return(nexus_info->pixels);
4876}
4877
4878/*
4879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4880% %
4881% %
4882% %
4883% 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 %
4884% %
4885% %
4886% %
4887%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4888%
4889% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4890% pixel cache and returns the previous setting. A virtual pixel is any pixel
4891% access that is outside the boundaries of the image cache.
4892%
4893% The format of the SetPixelCacheVirtualMethod() method is:
4894%
cristy387430f2012-02-07 13:09:46 +00004895% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4896% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004897%
4898% A description of each parameter follows:
4899%
4900% o image: the image.
4901%
4902% o virtual_pixel_method: choose the type of virtual pixel.
4903%
cristy387430f2012-02-07 13:09:46 +00004904% o exception: return any errors or warnings in this structure.
4905%
cristy3ed852e2009-09-05 21:47:34 +00004906*/
cristy3d4cb882012-02-07 19:11:26 +00004907
4908static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4909 ExceptionInfo *exception)
4910{
4911 CacheInfo
4912 *cache_info;
4913
cristyf2719112012-05-06 18:38:46 +00004914 CacheView
4915 *image_view;
4916
cristy3d4cb882012-02-07 19:11:26 +00004917 MagickBooleanType
4918 status;
4919
4920 ssize_t
4921 y;
4922
4923 assert(image != (Image *) NULL);
4924 assert(image->signature == MagickSignature);
4925 if (image->debug != MagickFalse)
4926 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4927 assert(image->cache != (Cache) NULL);
4928 cache_info=(CacheInfo *) image->cache;
4929 assert(cache_info->signature == MagickSignature);
cristy8a46d822012-08-28 23:32:39 +00004930 image->alpha_trait=BlendPixelTrait;
cristy3d4cb882012-02-07 19:11:26 +00004931 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004932 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004933#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +00004934 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00004935 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004936#endif
4937 for (y=0; y < (ssize_t) image->rows; y++)
4938 {
cristy3d4cb882012-02-07 19:11:26 +00004939 register Quantum
4940 *restrict q;
4941
4942 register ssize_t
4943 x;
4944
4945 if (status == MagickFalse)
4946 continue;
cristy23d198a2012-03-13 13:48:08 +00004947 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004948 if (q == (Quantum *) NULL)
4949 {
4950 status=MagickFalse;
4951 continue;
4952 }
4953 for (x=0; x < (ssize_t) image->columns; x++)
4954 {
4955 SetPixelAlpha(image,alpha,q);
4956 q+=GetPixelChannels(image);
4957 }
cristy23d198a2012-03-13 13:48:08 +00004958 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004959 }
cristy23d198a2012-03-13 13:48:08 +00004960 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004961 return(status);
4962}
4963
cristy387430f2012-02-07 13:09:46 +00004964MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4965 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004966{
4967 CacheInfo
4968 *cache_info;
4969
4970 VirtualPixelMethod
4971 method;
4972
4973 assert(image != (Image *) NULL);
4974 assert(image->signature == MagickSignature);
4975 if (image->debug != MagickFalse)
4976 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4977 assert(image->cache != (Cache) NULL);
4978 cache_info=(CacheInfo *) image->cache;
4979 assert(cache_info->signature == MagickSignature);
4980 method=cache_info->virtual_pixel_method;
4981 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy13c10082012-05-29 11:22:12 +00004982 if ((image->columns != 0) && (image->rows != 0))
4983 switch (virtual_pixel_method)
cristy387430f2012-02-07 13:09:46 +00004984 {
cristy13c10082012-05-29 11:22:12 +00004985 case BackgroundVirtualPixelMethod:
4986 {
cristy8a46d822012-08-28 23:32:39 +00004987 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4988 (image->alpha_trait != BlendPixelTrait))
cristy13c10082012-05-29 11:22:12 +00004989 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy6386b792012-06-23 17:44:57 +00004990 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4991 (IsGrayColorspace(image->colorspace) != MagickFalse))
cristyb09db112012-07-11 12:04:31 +00004992 (void) TransformImageColorspace(image,RGBColorspace,exception);
cristy13c10082012-05-29 11:22:12 +00004993 break;
4994 }
4995 case TransparentVirtualPixelMethod:
4996 {
cristy8a46d822012-08-28 23:32:39 +00004997 if (image->alpha_trait != BlendPixelTrait)
cristy13c10082012-05-29 11:22:12 +00004998 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4999 break;
5000 }
5001 default:
5002 break;
cristy387430f2012-02-07 13:09:46 +00005003 }
cristy3ed852e2009-09-05 21:47:34 +00005004 return(method);
5005}
5006
5007/*
5008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5009% %
5010% %
5011% %
5012+ 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 %
5013% %
5014% %
5015% %
5016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5017%
5018% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5019% in-memory or disk cache. The method returns MagickTrue if the pixel region
5020% is synced, otherwise MagickFalse.
5021%
5022% The format of the SyncAuthenticPixelCacheNexus() method is:
5023%
5024% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5025% NexusInfo *nexus_info,ExceptionInfo *exception)
5026%
5027% A description of each parameter follows:
5028%
5029% o image: the image.
5030%
5031% o nexus_info: the cache nexus to sync.
5032%
5033% o exception: return any errors or warnings in this structure.
5034%
5035*/
cristya6577ff2011-09-02 19:54:26 +00005036MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005037 NexusInfo *nexus_info,ExceptionInfo *exception)
5038{
5039 CacheInfo
5040 *cache_info;
5041
5042 MagickBooleanType
5043 status;
5044
5045 /*
5046 Transfer pixels to the cache.
5047 */
5048 assert(image != (Image *) NULL);
5049 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005050 if (image->cache == (Cache) NULL)
5051 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5052 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005053 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005054 if (cache_info->type == UndefinedCache)
5055 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005056 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005057 return(MagickTrue);
5058 assert(cache_info->signature == MagickSignature);
5059 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005060 if ((cache_info->metacontent_extent != 0) &&
5061 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005062 return(MagickFalse);
5063 return(status);
5064}
5065
5066/*
5067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5068% %
5069% %
5070% %
5071+ S y n c A u t h e n t i c P i x e l C a c h e %
5072% %
5073% %
5074% %
5075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5076%
5077% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5078% or disk cache. The method returns MagickTrue if the pixel region is synced,
5079% otherwise MagickFalse.
5080%
5081% The format of the SyncAuthenticPixelsCache() method is:
5082%
5083% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5084% ExceptionInfo *exception)
5085%
5086% A description of each parameter follows:
5087%
5088% o image: the image.
5089%
5090% o exception: return any errors or warnings in this structure.
5091%
5092*/
5093static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5094 ExceptionInfo *exception)
5095{
5096 CacheInfo
5097 *cache_info;
5098
cristy5c9e6f22010-09-17 17:31:01 +00005099 const int
5100 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005101
cristy4c08aed2011-07-01 19:47:50 +00005102 MagickBooleanType
5103 status;
5104
cristye7cc7cf2010-09-21 13:26:47 +00005105 assert(image != (Image *) NULL);
5106 assert(image->signature == MagickSignature);
5107 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005108 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005109 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005110 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005111 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5112 exception);
5113 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005114}
5115
5116/*
5117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5118% %
5119% %
5120% %
5121% S y n c A u t h e n t i c P i x e l s %
5122% %
5123% %
5124% %
5125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5126%
5127% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5128% The method returns MagickTrue if the pixel region is flushed, otherwise
5129% MagickFalse.
5130%
5131% The format of the SyncAuthenticPixels() method is:
5132%
5133% MagickBooleanType SyncAuthenticPixels(Image *image,
5134% ExceptionInfo *exception)
5135%
5136% A description of each parameter follows:
5137%
5138% o image: the image.
5139%
5140% o exception: return any errors or warnings in this structure.
5141%
5142*/
5143MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5144 ExceptionInfo *exception)
5145{
5146 CacheInfo
5147 *cache_info;
5148
cristy2036f5c2010-09-19 21:18:17 +00005149 const int
5150 id = GetOpenMPThreadId();
5151
cristy4c08aed2011-07-01 19:47:50 +00005152 MagickBooleanType
5153 status;
5154
cristy3ed852e2009-09-05 21:47:34 +00005155 assert(image != (Image *) NULL);
5156 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005157 assert(image->cache != (Cache) NULL);
5158 cache_info=(CacheInfo *) image->cache;
5159 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005160 if (cache_info->methods.sync_authentic_pixels_handler !=
5161 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005162 {
5163 status=cache_info->methods.sync_authentic_pixels_handler(image,
5164 exception);
5165 return(status);
5166 }
cristy2036f5c2010-09-19 21:18:17 +00005167 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005168 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5169 exception);
5170 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005171}
5172
5173/*
5174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5175% %
5176% %
5177% %
cristyd1dd6e42011-09-04 01:46:08 +00005178+ 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 +00005179% %
5180% %
5181% %
5182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5183%
5184% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5185% The method returns MagickTrue if the pixel region is flushed, otherwise
5186% MagickFalse.
5187%
5188% The format of the SyncImagePixelCache() method is:
5189%
5190% MagickBooleanType SyncImagePixelCache(Image *image,
5191% ExceptionInfo *exception)
5192%
5193% A description of each parameter follows:
5194%
5195% o image: the image.
5196%
5197% o exception: return any errors or warnings in this structure.
5198%
5199*/
cristyd1dd6e42011-09-04 01:46:08 +00005200MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005201 ExceptionInfo *exception)
5202{
5203 CacheInfo
5204 *cache_info;
5205
5206 assert(image != (Image *) NULL);
5207 assert(exception != (ExceptionInfo *) NULL);
5208 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5209 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5210}
5211
5212/*
5213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5214% %
5215% %
5216% %
cristy4c08aed2011-07-01 19:47:50 +00005217+ 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 +00005218% %
5219% %
5220% %
5221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222%
cristy4c08aed2011-07-01 19:47:50 +00005223% WritePixelCacheMetacontent() writes the meta-content to the specified region
5224% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005225%
cristy4c08aed2011-07-01 19:47:50 +00005226% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005227%
cristy4c08aed2011-07-01 19:47:50 +00005228% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005229% NexusInfo *nexus_info,ExceptionInfo *exception)
5230%
5231% A description of each parameter follows:
5232%
5233% o cache_info: the pixel cache.
5234%
cristy4c08aed2011-07-01 19:47:50 +00005235% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005236%
5237% o exception: return any errors or warnings in this structure.
5238%
5239*/
cristy4c08aed2011-07-01 19:47:50 +00005240static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005241 NexusInfo *nexus_info,ExceptionInfo *exception)
5242{
5243 MagickOffsetType
5244 count,
5245 offset;
5246
5247 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005248 extent,
5249 length;
cristy3ed852e2009-09-05 21:47:34 +00005250
cristy4c08aed2011-07-01 19:47:50 +00005251 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005252 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005253
cristybb503372010-05-27 20:51:26 +00005254 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005255 y;
5256
cristybb503372010-05-27 20:51:26 +00005257 size_t
cristy3ed852e2009-09-05 21:47:34 +00005258 rows;
5259
cristy4c08aed2011-07-01 19:47:50 +00005260 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005261 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005262 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005263 return(MagickTrue);
5264 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5265 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005266 length=(MagickSizeType) nexus_info->region.width*
5267 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005268 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005269 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005270 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005271 switch (cache_info->type)
5272 {
5273 case MemoryCache:
5274 case MapCache:
5275 {
cristy4c08aed2011-07-01 19:47:50 +00005276 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005277 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005278
5279 /*
cristy4c08aed2011-07-01 19:47:50 +00005280 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005281 */
cristydd341db2010-03-04 19:06:38 +00005282 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005283 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005284 {
cristy48078b12010-09-23 17:11:01 +00005285 length=extent;
cristydd341db2010-03-04 19:06:38 +00005286 rows=1UL;
5287 }
cristy4c08aed2011-07-01 19:47:50 +00005288 q=(unsigned char *) cache_info->metacontent+offset*
5289 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005290 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005291 {
cristy8f036fe2010-09-18 02:02:00 +00005292 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005293 p+=nexus_info->region.width*cache_info->metacontent_extent;
5294 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005295 }
5296 break;
5297 }
5298 case DiskCache:
5299 {
5300 /*
cristy4c08aed2011-07-01 19:47:50 +00005301 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005302 */
5303 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5304 {
5305 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5306 cache_info->cache_filename);
5307 return(MagickFalse);
5308 }
cristydd341db2010-03-04 19:06:38 +00005309 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005310 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005311 {
cristy48078b12010-09-23 17:11:01 +00005312 length=extent;
cristydd341db2010-03-04 19:06:38 +00005313 rows=1UL;
5314 }
cristy48078b12010-09-23 17:11:01 +00005315 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005316 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005317 {
cristy48078b12010-09-23 17:11:01 +00005318 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005319 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005320 cache_info->metacontent_extent,length,(const unsigned char *) p);
5321 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005322 break;
cristy4c08aed2011-07-01 19:47:50 +00005323 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005324 offset+=cache_info->columns;
5325 }
cristyc11dace2012-01-24 16:39:46 +00005326 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5327 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005328 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005329 {
5330 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5331 cache_info->cache_filename);
5332 return(MagickFalse);
5333 }
5334 break;
5335 }
5336 default:
5337 break;
5338 }
5339 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005340 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005341 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005342 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005343 nexus_info->region.width,(double) nexus_info->region.height,(double)
5344 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005345 return(MagickTrue);
5346}
5347
5348/*
5349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5350% %
5351% %
5352% %
5353+ W r i t e C a c h e P i x e l s %
5354% %
5355% %
5356% %
5357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5358%
5359% WritePixelCachePixels() writes image pixels to the specified region of the
5360% pixel cache.
5361%
5362% The format of the WritePixelCachePixels() method is:
5363%
5364% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5365% NexusInfo *nexus_info,ExceptionInfo *exception)
5366%
5367% A description of each parameter follows:
5368%
5369% o cache_info: the pixel cache.
5370%
5371% o nexus_info: the cache nexus to write the pixels.
5372%
5373% o exception: return any errors or warnings in this structure.
5374%
5375*/
5376static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5377 NexusInfo *nexus_info,ExceptionInfo *exception)
5378{
5379 MagickOffsetType
5380 count,
5381 offset;
5382
5383 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005384 extent,
5385 length;
cristy3ed852e2009-09-05 21:47:34 +00005386
cristy4c08aed2011-07-01 19:47:50 +00005387 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005388 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005389
cristybb503372010-05-27 20:51:26 +00005390 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005391 y;
5392
cristybb503372010-05-27 20:51:26 +00005393 size_t
cristy3ed852e2009-09-05 21:47:34 +00005394 rows;
5395
cristy4c08aed2011-07-01 19:47:50 +00005396 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005397 return(MagickTrue);
5398 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5399 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005400 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005401 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005402 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005403 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005404 p=nexus_info->pixels;
5405 switch (cache_info->type)
5406 {
5407 case MemoryCache:
5408 case MapCache:
5409 {
cristy4c08aed2011-07-01 19:47:50 +00005410 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005411 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005412
5413 /*
5414 Write pixels to memory.
5415 */
cristydd341db2010-03-04 19:06:38 +00005416 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005417 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005418 {
cristy48078b12010-09-23 17:11:01 +00005419 length=extent;
cristydd341db2010-03-04 19:06:38 +00005420 rows=1UL;
5421 }
cristyed231572011-07-14 02:18:59 +00005422 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005423 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005424 {
cristy8f036fe2010-09-18 02:02:00 +00005425 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005426 p+=nexus_info->region.width*cache_info->number_channels;
5427 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005428 }
5429 break;
5430 }
5431 case DiskCache:
5432 {
5433 /*
5434 Write pixels to disk.
5435 */
5436 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5437 {
5438 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5439 cache_info->cache_filename);
5440 return(MagickFalse);
5441 }
cristydd341db2010-03-04 19:06:38 +00005442 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005443 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005444 {
cristy48078b12010-09-23 17:11:01 +00005445 length=extent;
cristydd341db2010-03-04 19:06:38 +00005446 rows=1UL;
5447 }
cristybb503372010-05-27 20:51:26 +00005448 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005449 {
5450 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005451 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005452 p);
5453 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005454 break;
cristyed231572011-07-14 02:18:59 +00005455 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005456 offset+=cache_info->columns;
5457 }
cristyc11dace2012-01-24 16:39:46 +00005458 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5459 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005460 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005461 {
5462 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5463 cache_info->cache_filename);
5464 return(MagickFalse);
5465 }
5466 break;
5467 }
5468 default:
5469 break;
5470 }
5471 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005472 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005473 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005474 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005475 nexus_info->region.width,(double) nexus_info->region.height,(double)
5476 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005477 return(MagickTrue);
5478}