blob: d04180453a26df9b640286e727099a67fc0c4aef [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
cristy3d9f5ba2012-06-26 13:37:31 +000049#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000050#include "MagickCore/composite-private.h"
51#include "MagickCore/exception.h"
52#include "MagickCore/exception-private.h"
53#include "MagickCore/geometry.h"
54#include "MagickCore/list.h"
55#include "MagickCore/log.h"
56#include "MagickCore/magick.h"
57#include "MagickCore/memory_.h"
cristyadf82722012-05-11 17:34:16 +000058#include "MagickCore/memory-private.h"
cristyd2d11ec2012-03-28 13:53:49 +000059#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000060#include "MagickCore/pixel.h"
61#include "MagickCore/pixel-accessor.h"
62#include "MagickCore/policy.h"
63#include "MagickCore/quantum.h"
64#include "MagickCore/random_.h"
65#include "MagickCore/resource_.h"
66#include "MagickCore/semaphore.h"
67#include "MagickCore/splay-tree.h"
68#include "MagickCore/string_.h"
69#include "MagickCore/string-private.h"
70#include "MagickCore/thread-private.h"
71#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000072#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000073#if defined(MAGICKCORE_ZLIB_DELEGATE)
74#include "zlib.h"
75#endif
76
77/*
cristy30097232010-07-01 02:16:30 +000078 Define declarations.
79*/
80#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
cristyc11dace2012-01-24 16:39:46 +000081#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
82 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
cristy30097232010-07-01 02:16:30 +000083
84/*
cristy3ed852e2009-09-05 21:47:34 +000085 Typedef declarations.
86*/
87typedef struct _MagickModulo
88{
cristybb503372010-05-27 20:51:26 +000089 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000090 quotient,
91 remainder;
92} MagickModulo;
93
94struct _NexusInfo
95{
96 MagickBooleanType
97 mapped;
98
99 RectangleInfo
100 region;
101
102 MagickSizeType
103 length;
104
cristy4c08aed2011-07-01 19:47:50 +0000105 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000106 *cache,
107 *pixels;
108
cristy4c08aed2011-07-01 19:47:50 +0000109 void
110 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000111
cristybb503372010-05-27 20:51:26 +0000112 size_t
cristy3ed852e2009-09-05 21:47:34 +0000113 signature;
114};
115
116/*
117 Forward declarations.
118*/
119#if defined(__cplusplus) || defined(c_plusplus)
120extern "C" {
121#endif
122
cristy19596d62012-02-19 00:24:59 +0000123static Cache
124 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
125 magick_hot_spot;
126
cristy4c08aed2011-07-01 19:47:50 +0000127static const Quantum
cristybb503372010-05-27 20:51:26 +0000128 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000129 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 *GetVirtualPixelsCache(const Image *);
131
cristy4c08aed2011-07-01 19:47:50 +0000132static const void
133 *GetVirtualMetacontentFromCache(const Image *);
134
cristy3ed852e2009-09-05 21:47:34 +0000135static MagickBooleanType
cristy74ce05d2012-05-06 18:41:18 +0000136 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
137 ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000138 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000139 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000140 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000141 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
143 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000144 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000145 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
146
cristy4c08aed2011-07-01 19:47:50 +0000147static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000148 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
149 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000150 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
151 const size_t,ExceptionInfo *),
cristy265a2b22012-05-11 12:48:50 +0000152 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
153 NexusInfo *,ExceptionInfo *) magick_hot_spot;
cristy3ed852e2009-09-05 21:47:34 +0000154
155#if defined(__cplusplus) || defined(c_plusplus)
156}
157#endif
158
159/*
160 Global declarations.
161*/
162static volatile MagickBooleanType
163 instantiate_cache = MagickFalse;
164
165static SemaphoreInfo
166 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000167
168/*
169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170% %
171% %
172% %
173+ A c q u i r e P i x e l C a c h e %
174% %
175% %
176% %
177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178%
179% AcquirePixelCache() acquires a pixel cache.
180%
181% The format of the AcquirePixelCache() method is:
182%
cristybb503372010-05-27 20:51:26 +0000183% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184%
185% A description of each parameter follows:
186%
187% o number_threads: the number of nexus threads.
188%
189*/
cristya6577ff2011-09-02 19:54:26 +0000190MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000191{
192 CacheInfo
193 *cache_info;
194
cristya64b85d2011-09-14 01:02:31 +0000195 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000196 if (cache_info == (CacheInfo *) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
199 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000200 cache_info->mode=IOMode;
cristyc511e882012-04-16 21:11:14 +0000201 cache_info->colorspace=sRGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +0000202 cache_info->file=(-1);
203 cache_info->id=GetMagickThreadId();
204 cache_info->number_threads=number_threads;
cristyd99b5a52012-10-27 23:07:47 +0000205 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
206 cache_info->number_threads=GetOpenMPMaximumThreads();
207 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
cristy9357bdd2012-07-30 12:28:34 +0000208 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
cristy134c76e2012-08-05 01:21:44 +0000209 if (cache_info->number_threads == 0)
210 cache_info->number_threads=1;
cristy3ed852e2009-09-05 21:47:34 +0000211 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
212 if (cache_info->nexus_info == (NexusInfo **) NULL)
213 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000214 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000215 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000216 cache_info->disk_semaphore=AllocateSemaphoreInfo();
217 cache_info->debug=IsEventLogging();
218 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000219 return((Cache ) cache_info);
220}
221
222/*
223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224% %
225% %
226% %
227% A c q u i r e P i x e l C a c h e N e x u s %
228% %
229% %
230% %
231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232%
233% AcquirePixelCacheNexus() allocates the NexusInfo structure.
234%
235% The format of the AcquirePixelCacheNexus method is:
236%
cristybb503372010-05-27 20:51:26 +0000237% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000238%
239% A description of each parameter follows:
240%
241% o number_threads: the number of nexus threads.
242%
243*/
cristya6577ff2011-09-02 19:54:26 +0000244MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000245{
cristy3ed852e2009-09-05 21:47:34 +0000246 NexusInfo
247 **nexus_info;
248
cristye076a6e2010-08-15 19:59:43 +0000249 register ssize_t
250 i;
251
cristye42639a2012-08-23 01:53:24 +0000252 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
253 number_threads,sizeof(*nexus_info)));
cristy3ed852e2009-09-05 21:47:34 +0000254 if (nexus_info == (NexusInfo **) NULL)
255 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000256 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
257 sizeof(**nexus_info));
258 if (nexus_info[0] == (NexusInfo *) NULL)
259 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
260 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
cristye5f87c82012-02-14 12:44:17 +0000263 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000264 nexus_info[i]->signature=MagickSignature;
265 }
266 return(nexus_info);
267}
268
269/*
270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271% %
272% %
273% %
cristyd43a46b2010-01-21 02:13:41 +0000274+ A c q u i r e P i x e l C a c h e P i x e l s %
275% %
276% %
277% %
278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279%
280% AcquirePixelCachePixels() returns the pixels associated with the specified
281% image.
282%
283% The format of the AcquirePixelCachePixels() method is:
284%
285% const void *AcquirePixelCachePixels(const Image *image,
286% MagickSizeType *length,ExceptionInfo *exception)
287%
288% A description of each parameter follows:
289%
290% o image: the image.
291%
292% o length: the pixel cache length.
293%
294% o exception: return any errors or warnings in this structure.
295%
296*/
cristyd1dd6e42011-09-04 01:46:08 +0000297MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000298 MagickSizeType *length,ExceptionInfo *exception)
299{
300 CacheInfo
301 *cache_info;
302
303 assert(image != (const Image *) NULL);
304 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000305 assert(exception != (ExceptionInfo *) NULL);
306 assert(exception->signature == MagickSignature);
307 assert(image->cache != (Cache) NULL);
308 cache_info=(CacheInfo *) image->cache;
309 assert(cache_info->signature == MagickSignature);
310 *length=0;
311 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
312 return((const void *) NULL);
313 *length=cache_info->length;
314 return((const void *) cache_info->pixels);
315}
316
317/*
318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319% %
320% %
321% %
cristyf34a1452009-10-24 22:29:27 +0000322+ C a c h e C o m p o n e n t G e n e s i s %
323% %
324% %
325% %
326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327%
328% CacheComponentGenesis() instantiates the cache component.
329%
330% The format of the CacheComponentGenesis method is:
331%
332% MagickBooleanType CacheComponentGenesis(void)
333%
334*/
cristy5ff4eaf2011-09-03 01:38:02 +0000335MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000336{
cristy165b6092009-10-26 13:52:10 +0000337 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000338 return(MagickTrue);
339}
340
341/*
342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343% %
344% %
345% %
346+ C a c h e C o m p o n e n t T e r m i n u s %
347% %
348% %
349% %
350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351%
352% CacheComponentTerminus() destroys the cache component.
353%
354% The format of the CacheComponentTerminus() method is:
355%
356% CacheComponentTerminus(void)
357%
358*/
cristy5ff4eaf2011-09-03 01:38:02 +0000359MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000360{
cristy18b17442009-10-25 18:36:48 +0000361 if (cache_semaphore == (SemaphoreInfo *) NULL)
362 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000363 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000364 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000365 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000366 DestroySemaphoreInfo(&cache_semaphore);
367}
368
369/*
370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371% %
372% %
373% %
cristy3ed852e2009-09-05 21:47:34 +0000374+ C l o n e P i x e l C a c h e %
375% %
376% %
377% %
378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379%
380% ClonePixelCache() clones a pixel cache.
381%
382% The format of the ClonePixelCache() method is:
383%
384% Cache ClonePixelCache(const Cache cache)
385%
386% A description of each parameter follows:
387%
388% o cache: the pixel cache.
389%
390*/
cristya6577ff2011-09-02 19:54:26 +0000391MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000392{
393 CacheInfo
394 *clone_info;
395
396 const CacheInfo
397 *cache_info;
398
cristy9f027d12011-09-21 01:17:17 +0000399 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000400 cache_info=(const CacheInfo *) cache;
401 assert(cache_info->signature == MagickSignature);
402 if (cache_info->debug != MagickFalse)
403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
404 cache_info->filename);
405 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
406 if (clone_info == (Cache) NULL)
407 return((Cache) NULL);
408 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
409 return((Cache ) clone_info);
410}
411
412/*
413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
414% %
415% %
416% %
cristy60c44a82009-10-07 00:58:49 +0000417+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000418% %
419% %
420% %
421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
422% ClonePixelCachePixels() clones the source pixel cache to the destination
423% cache.
424%
425% The format of the ClonePixelCachePixels() method is:
426%
427% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
428% CacheInfo *source_info,ExceptionInfo *exception)
429%
430% A description of each parameter follows:
431%
432% o cache_info: the pixel cache.
433%
434% o source_info: the source pixel cache.
435%
436% o exception: return any errors or warnings in this structure.
437%
438*/
439
440static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
441{
442 int
443 status;
444
cristy5ee247a2010-02-12 15:42:34 +0000445 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000446 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000447 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000448 {
449 status=close(cache_info->file);
450 cache_info->file=(-1);
451 RelinquishMagickResource(FileResource,1);
452 }
cristyf84a1932010-01-03 18:00:18 +0000453 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000454 return(status == -1 ? MagickFalse : MagickTrue);
455}
456
cristy3ed852e2009-09-05 21:47:34 +0000457static inline MagickSizeType MagickMax(const MagickSizeType x,
458 const MagickSizeType y)
459{
460 if (x > y)
461 return(x);
462 return(y);
463}
464
465static inline MagickSizeType MagickMin(const MagickSizeType x,
466 const MagickSizeType y)
467{
468 if (x < y)
469 return(x);
470 return(y);
471}
472
473static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
474 const MapMode mode)
475{
476 int
477 file;
478
479 /*
480 Open pixel cache on disk.
481 */
cristyf84a1932010-01-03 18:00:18 +0000482 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000483 if (cache_info->file != -1)
484 {
cristyf84a1932010-01-03 18:00:18 +0000485 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000486 return(MagickTrue); /* cache already open */
487 }
cristy3ed852e2009-09-05 21:47:34 +0000488 if (*cache_info->cache_filename == '\0')
489 file=AcquireUniqueFileResource(cache_info->cache_filename);
490 else
491 switch (mode)
492 {
493 case ReadMode:
494 {
cristy18c6c272011-09-23 14:40:37 +0000495 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000496 break;
497 }
498 case WriteMode:
499 {
cristy18c6c272011-09-23 14:40:37 +0000500 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
501 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000502 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000503 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000504 break;
505 }
506 case IOMode:
507 default:
508 {
cristy18c6c272011-09-23 14:40:37 +0000509 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000510 O_EXCL,S_MODE);
511 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000512 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000513 break;
514 }
515 }
516 if (file == -1)
517 {
cristyf84a1932010-01-03 18:00:18 +0000518 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000519 return(MagickFalse);
520 }
521 (void) AcquireMagickResource(FileResource,1);
522 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000523 cache_info->mode=mode;
cristyf84a1932010-01-03 18:00:18 +0000524 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000525 return(MagickTrue);
526}
527
cristyf1832792012-05-08 18:38:18 +0000528static inline MagickOffsetType ReadPixelCacheRegion(
529 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
530 const MagickSizeType length,unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000531{
532 register MagickOffsetType
533 i;
534
535 ssize_t
536 count;
537
538#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000539 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000540 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000541 {
cristyf84a1932010-01-03 18:00:18 +0000542 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000543 return((MagickOffsetType) -1);
544 }
545#endif
546 count=0;
547 for (i=0; i < (MagickOffsetType) length; i+=count)
548 {
549#if !defined(MAGICKCORE_HAVE_PREAD)
550 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
551 (MagickSizeType) SSIZE_MAX));
552#else
553 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000554 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000555#endif
cristy0bcbb402012-10-21 00:55:09 +0000556 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000557 {
cristy0bcbb402012-10-21 00:55:09 +0000558 count=0;
559 if (errno != EINTR)
560 break;
cristy3ed852e2009-09-05 21:47:34 +0000561 }
562 }
563#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000564 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000565#endif
566 return(i);
567}
568
cristyf1832792012-05-08 18:38:18 +0000569static inline MagickOffsetType WritePixelCacheRegion(
570 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
571 const MagickSizeType length,const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000572{
573 register MagickOffsetType
574 i;
575
576 ssize_t
577 count;
578
579#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000580 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000581 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000582 {
cristyf84a1932010-01-03 18:00:18 +0000583 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000584 return((MagickOffsetType) -1);
585 }
586#endif
587 count=0;
588 for (i=0; i < (MagickOffsetType) length; i+=count)
589 {
590#if !defined(MAGICKCORE_HAVE_PWRITE)
591 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
592 (MagickSizeType) SSIZE_MAX));
593#else
594 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000595 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000596#endif
cristy0bcbb402012-10-21 00:55:09 +0000597 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000598 {
cristy0bcbb402012-10-21 00:55:09 +0000599 count=0;
600 if (errno != EINTR)
601 break;
cristy3ed852e2009-09-05 21:47:34 +0000602 }
603 }
604#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000605 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000606#endif
607 return(i);
608}
609
cristy4c08aed2011-07-01 19:47:50 +0000610static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000611 CacheInfo *cache_info,ExceptionInfo *exception)
612{
613 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000614 count;
cristy3ed852e2009-09-05 21:47:34 +0000615
cristy4c08aed2011-07-01 19:47:50 +0000616 register MagickOffsetType
617 i;
cristye076a6e2010-08-15 19:59:43 +0000618
cristybb503372010-05-27 20:51:26 +0000619 size_t
cristy4c08aed2011-07-01 19:47:50 +0000620 length;
cristy3ed852e2009-09-05 21:47:34 +0000621
cristy4c08aed2011-07-01 19:47:50 +0000622 unsigned char
623 *blob;
624
625 /*
626 Clone pixel cache (both caches on disk).
627 */
cristy3ed852e2009-09-05 21:47:34 +0000628 if (cache_info->debug != MagickFalse)
629 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000630 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000631 sizeof(*blob));
632 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000633 {
cristy4c08aed2011-07-01 19:47:50 +0000634 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000635 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000636 cache_info->filename);
637 return(MagickFalse);
638 }
cristy3dedf062011-07-02 14:07:40 +0000639 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000640 {
641 blob=(unsigned char *) RelinquishMagickMemory(blob);
642 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
643 cache_info->cache_filename);
644 return(MagickFalse);
645 }
cristy3dedf062011-07-02 14:07:40 +0000646 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000647 {
648 (void) ClosePixelCacheOnDisk(cache_info);
649 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000650 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
651 clone_info->cache_filename);
652 return(MagickFalse);
653 }
cristy4c08aed2011-07-01 19:47:50 +0000654 count=0;
655 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000656 {
cristy4c08aed2011-07-01 19:47:50 +0000657 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
658 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
659 blob);
660 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000661 {
cristy4c08aed2011-07-01 19:47:50 +0000662 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
663 cache_info->cache_filename);
664 break;
cristy3ed852e2009-09-05 21:47:34 +0000665 }
cristy4c08aed2011-07-01 19:47:50 +0000666 length=(size_t) count;
667 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
668 if ((MagickSizeType) count != length)
669 {
670 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
671 clone_info->cache_filename);
672 break;
673 }
674 }
675 (void) ClosePixelCacheOnDisk(clone_info);
676 (void) ClosePixelCacheOnDisk(cache_info);
677 blob=(unsigned char *) RelinquishMagickMemory(blob);
678 if (i < (MagickOffsetType) cache_info->length)
679 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000680 return(MagickTrue);
681}
682
cristyfd24a062012-01-02 14:46:34 +0000683static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000684 CacheInfo *cache_info,ExceptionInfo *exception)
685{
686 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000687 count;
cristy3ed852e2009-09-05 21:47:34 +0000688
cristy4c08aed2011-07-01 19:47:50 +0000689 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000690 {
cristy3ed852e2009-09-05 21:47:34 +0000691 /*
cristy4c08aed2011-07-01 19:47:50 +0000692 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000693 */
cristy4c08aed2011-07-01 19:47:50 +0000694 if (cache_info->debug != MagickFalse)
695 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
696 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
697 cache_info->length);
698 return(MagickTrue);
699 }
700 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
701 {
702 /*
703 Clone pixel cache (one cache on disk, one in memory).
704 */
705 if (cache_info->debug != MagickFalse)
706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
707 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000708 {
cristy4c08aed2011-07-01 19:47:50 +0000709 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000710 cache_info->cache_filename);
711 return(MagickFalse);
712 }
cristy4c08aed2011-07-01 19:47:50 +0000713 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
714 cache_info->length,(unsigned char *) clone_info->pixels);
715 (void) ClosePixelCacheOnDisk(cache_info);
716 if ((MagickSizeType) count != cache_info->length)
717 {
718 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
719 cache_info->cache_filename);
720 return(MagickFalse);
721 }
722 return(MagickTrue);
723 }
724 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
725 {
726 /*
727 Clone pixel cache (one cache on disk, one in memory).
728 */
729 if (clone_info->debug != MagickFalse)
730 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
731 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
732 {
733 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
734 clone_info->cache_filename);
735 return(MagickFalse);
736 }
737 count=WritePixelCacheRegion(clone_info,clone_info->offset,
738 clone_info->length,(unsigned char *) cache_info->pixels);
739 (void) ClosePixelCacheOnDisk(clone_info);
740 if ((MagickSizeType) count != clone_info->length)
741 {
742 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
743 clone_info->cache_filename);
744 return(MagickFalse);
745 }
746 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000747 }
748 /*
cristy4c08aed2011-07-01 19:47:50 +0000749 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000750 */
cristy4c08aed2011-07-01 19:47:50 +0000751 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000752}
753
cristyfd24a062012-01-02 14:46:34 +0000754static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000755 CacheInfo *cache_info,ExceptionInfo *exception)
756{
cristy4c08aed2011-07-01 19:47:50 +0000757 MagickBooleanType
758 status;
cristy3ed852e2009-09-05 21:47:34 +0000759
cristy4c08aed2011-07-01 19:47:50 +0000760 MagickOffsetType
761 cache_offset,
762 clone_offset,
763 count;
764
765 register ssize_t
766 x;
767
cristyfd24a062012-01-02 14:46:34 +0000768 register unsigned char
769 *p;
770
cristy4c08aed2011-07-01 19:47:50 +0000771 size_t
cristy3ed852e2009-09-05 21:47:34 +0000772 length;
773
cristy4c08aed2011-07-01 19:47:50 +0000774 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000775 y;
776
cristy4c08aed2011-07-01 19:47:50 +0000777 unsigned char
778 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000779
cristy4c08aed2011-07-01 19:47:50 +0000780 /*
781 Clone pixel cache (unoptimized).
782 */
cristy3ed852e2009-09-05 21:47:34 +0000783 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000784 {
cristy4c08aed2011-07-01 19:47:50 +0000785 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
787 else
788 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
789 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
790 else
791 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
792 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
793 else
794 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
795 }
cristyed231572011-07-14 02:18:59 +0000796 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
797 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000798 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000799 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000800 if (blob == (unsigned char *) NULL)
801 {
802 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000803 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000804 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000805 return(MagickFalse);
806 }
cristy4c08aed2011-07-01 19:47:50 +0000807 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
808 cache_offset=0;
809 clone_offset=0;
810 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000811 {
cristy4c08aed2011-07-01 19:47:50 +0000812 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000813 {
cristy4c08aed2011-07-01 19:47:50 +0000814 blob=(unsigned char *) RelinquishMagickMemory(blob);
815 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000816 cache_info->cache_filename);
817 return(MagickFalse);
818 }
cristy4c08aed2011-07-01 19:47:50 +0000819 cache_offset=cache_info->offset;
820 }
821 if (clone_info->type == DiskCache)
822 {
cristy3dedf062011-07-02 14:07:40 +0000823 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000824 {
cristy4c08aed2011-07-01 19:47:50 +0000825 blob=(unsigned char *) RelinquishMagickMemory(blob);
826 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
827 clone_info->cache_filename);
828 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000829 }
cristy4c08aed2011-07-01 19:47:50 +0000830 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000831 }
832 /*
cristy4c08aed2011-07-01 19:47:50 +0000833 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000834 */
cristy4c08aed2011-07-01 19:47:50 +0000835 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000836 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000837 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000838 {
cristy4c08aed2011-07-01 19:47:50 +0000839 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000840 {
cristy9e0719b2011-12-29 03:45:45 +0000841 register ssize_t
842 i;
843
cristy3ed852e2009-09-05 21:47:34 +0000844 /*
cristy4c08aed2011-07-01 19:47:50 +0000845 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000846 */
cristyed231572011-07-14 02:18:59 +0000847 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000848 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000849 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000850 else
851 {
cristyfd24a062012-01-02 14:46:34 +0000852 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000853 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000854 {
cristy4c08aed2011-07-01 19:47:50 +0000855 status=MagickFalse;
856 break;
cristy3ed852e2009-09-05 21:47:34 +0000857 }
858 }
cristy4c08aed2011-07-01 19:47:50 +0000859 cache_offset+=length;
860 if ((y < (ssize_t) clone_info->rows) &&
861 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000862 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000863 {
cristy9e0719b2011-12-29 03:45:45 +0000864 PixelChannel
865 channel;
866
867 PixelTrait
868 traits;
869
870 ssize_t
871 offset;
872
cristy4c08aed2011-07-01 19:47:50 +0000873 /*
cristy3b8fe922011-12-29 18:56:23 +0000874 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000875 */
cristy9e0719b2011-12-29 03:45:45 +0000876 channel=clone_info->channel_map[i].channel;
877 traits=cache_info->channel_map[channel].traits;
878 if (traits == UndefinedPixelTrait)
879 {
cristy0f4425e2011-12-31 20:33:02 +0000880 clone_offset+=sizeof(Quantum);
881 continue;
cristy9e0719b2011-12-29 03:45:45 +0000882 }
cristy0f4425e2011-12-31 20:33:02 +0000883 offset=cache_info->channel_map[channel].offset;
884 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000885 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
886 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000887 else
888 {
cristy0f4425e2011-12-31 20:33:02 +0000889 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000890 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000891 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000892 {
cristy0f4425e2011-12-31 20:33:02 +0000893 status=MagickFalse;
894 break;
cristy4c08aed2011-07-01 19:47:50 +0000895 }
896 }
cristy9e0719b2011-12-29 03:45:45 +0000897 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000898 }
899 }
cristyac245f82012-05-05 17:13:57 +0000900 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000901 {
902 /*
903 Set remaining columns as undefined.
904 */
cristy888e6132012-04-23 19:54:54 +0000905 length=clone_info->number_channels*sizeof(Quantum);
906 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
907 for ( ; x < (ssize_t) clone_info->columns; x++)
908 {
909 if (clone_info->type != DiskCache)
910 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
911 blob,length);
912 else
913 {
914 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
915 if ((MagickSizeType) count != length)
916 {
917 status=MagickFalse;
918 break;
cristye04362f2012-04-23 15:33:05 +0000919 }
cristy888e6132012-04-23 19:54:54 +0000920 }
921 clone_offset+=length;
922 }
cristye04362f2012-04-23 15:33:05 +0000923 }
cristy4c08aed2011-07-01 19:47:50 +0000924 }
cristyed231572011-07-14 02:18:59 +0000925 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000926 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
927 for ( ; y < (ssize_t) clone_info->rows; y++)
928 {
929 /*
cristy9e0719b2011-12-29 03:45:45 +0000930 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000931 */
932 for (x=0; x < (ssize_t) clone_info->columns; x++)
933 {
934 if (clone_info->type != DiskCache)
935 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
936 length);
937 else
938 {
939 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
940 if ((MagickSizeType) count != length)
941 {
942 status=MagickFalse;
943 break;
944 }
945 }
946 clone_offset+=length;
947 }
948 }
cristy9e0719b2011-12-29 03:45:45 +0000949 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000950 (clone_info->metacontent_extent != 0))
951 {
952 /*
953 Clone metacontent.
954 */
955 for (y=0; y < (ssize_t) cache_info->rows; y++)
956 {
957 for (x=0; x < (ssize_t) cache_info->columns; x++)
958 {
959 /*
960 Read a set of metacontent.
961 */
962 length=cache_info->metacontent_extent;
963 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000964 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000965 else
966 {
cristyfd24a062012-01-02 14:46:34 +0000967 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000968 if ((MagickSizeType) count != length)
969 {
970 status=MagickFalse;
971 break;
972 }
973 }
974 cache_offset+=length;
975 if ((y < (ssize_t) clone_info->rows) &&
976 (x < (ssize_t) clone_info->columns))
977 {
978 /*
979 Write a set of metacontent.
980 */
981 length=clone_info->metacontent_extent;
982 if (clone_info->type != DiskCache)
983 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000984 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000985 else
986 {
cristyfd24a062012-01-02 14:46:34 +0000987 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000988 if ((MagickSizeType) count != length)
989 {
990 status=MagickFalse;
991 break;
992 }
993 }
994 clone_offset+=length;
995 }
996 }
997 length=clone_info->metacontent_extent;
998 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
999 for ( ; x < (ssize_t) clone_info->columns; x++)
1000 {
1001 /*
cristy9e0719b2011-12-29 03:45:45 +00001002 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001003 */
1004 if (clone_info->type != DiskCache)
1005 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1006 blob,length);
1007 else
1008 {
cristy208b1002011-08-07 18:51:50 +00001009 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001010 if ((MagickSizeType) count != length)
1011 {
1012 status=MagickFalse;
1013 break;
1014 }
1015 }
1016 clone_offset+=length;
1017 }
1018 }
cristyac245f82012-05-05 17:13:57 +00001019 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001020 {
cristye04362f2012-04-23 15:33:05 +00001021 /*
1022 Set remaining rows as undefined.
1023 */
cristy888e6132012-04-23 19:54:54 +00001024 length=clone_info->metacontent_extent;
1025 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1026 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001027 {
cristy888e6132012-04-23 19:54:54 +00001028 for (x=0; x < (ssize_t) clone_info->columns; x++)
1029 {
1030 if (clone_info->type != DiskCache)
1031 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1032 blob,length);
1033 else
1034 {
1035 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1036 blob);
1037 if ((MagickSizeType) count != length)
1038 {
1039 status=MagickFalse;
1040 break;
1041 }
1042 }
1043 clone_offset+=length;
1044 }
cristye04362f2012-04-23 15:33:05 +00001045 }
cristy4c08aed2011-07-01 19:47:50 +00001046 }
cristy4c08aed2011-07-01 19:47:50 +00001047 }
1048 if (clone_info->type == DiskCache)
1049 (void) ClosePixelCacheOnDisk(clone_info);
1050 if (cache_info->type == DiskCache)
1051 (void) ClosePixelCacheOnDisk(cache_info);
1052 blob=(unsigned char *) RelinquishMagickMemory(blob);
1053 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001054}
1055
1056static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1057 CacheInfo *cache_info,ExceptionInfo *exception)
1058{
cristy3dfccb22011-12-28 21:47:20 +00001059 PixelChannelMap
1060 *p,
1061 *q;
1062
cristy5a7fbfb2010-11-06 16:10:59 +00001063 if (cache_info->type == PingCache)
1064 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001065 p=cache_info->channel_map;
1066 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001067 if ((cache_info->columns == clone_info->columns) &&
1068 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001069 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001070 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001071 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001072 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1073 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001074}
1075
1076/*
1077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078% %
1079% %
1080% %
1081+ C l o n e P i x e l C a c h e M e t h o d s %
1082% %
1083% %
1084% %
1085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086%
1087% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1088% another.
1089%
1090% The format of the ClonePixelCacheMethods() method is:
1091%
1092% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1093%
1094% A description of each parameter follows:
1095%
1096% o clone: Specifies a pointer to a Cache structure.
1097%
1098% o cache: the pixel cache.
1099%
1100*/
cristya6577ff2011-09-02 19:54:26 +00001101MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001102{
1103 CacheInfo
1104 *cache_info,
1105 *source_info;
1106
1107 assert(clone != (Cache) NULL);
1108 source_info=(CacheInfo *) clone;
1109 assert(source_info->signature == MagickSignature);
1110 if (source_info->debug != MagickFalse)
1111 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1112 source_info->filename);
1113 assert(cache != (Cache) NULL);
1114 cache_info=(CacheInfo *) cache;
1115 assert(cache_info->signature == MagickSignature);
1116 source_info->methods=cache_info->methods;
1117}
1118
1119/*
1120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1121% %
1122% %
1123% %
1124+ D e s t r o y I m a g e P i x e l C a c h e %
1125% %
1126% %
1127% %
1128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1129%
1130% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1131%
1132% The format of the DestroyImagePixelCache() method is:
1133%
1134% void DestroyImagePixelCache(Image *image)
1135%
1136% A description of each parameter follows:
1137%
1138% o image: the image.
1139%
1140*/
1141static void DestroyImagePixelCache(Image *image)
1142{
1143 assert(image != (Image *) NULL);
1144 assert(image->signature == MagickSignature);
1145 if (image->debug != MagickFalse)
1146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1147 if (image->cache == (void *) NULL)
1148 return;
1149 image->cache=DestroyPixelCache(image->cache);
1150}
1151
1152/*
1153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1154% %
1155% %
1156% %
1157+ D e s t r o y I m a g e P i x e l s %
1158% %
1159% %
1160% %
1161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162%
1163% DestroyImagePixels() deallocates memory associated with the pixel cache.
1164%
1165% The format of the DestroyImagePixels() method is:
1166%
1167% void DestroyImagePixels(Image *image)
1168%
1169% A description of each parameter follows:
1170%
1171% o image: the image.
1172%
1173*/
1174MagickExport void DestroyImagePixels(Image *image)
1175{
1176 CacheInfo
1177 *cache_info;
1178
1179 assert(image != (const Image *) NULL);
1180 assert(image->signature == MagickSignature);
1181 if (image->debug != MagickFalse)
1182 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1183 assert(image->cache != (Cache) NULL);
1184 cache_info=(CacheInfo *) image->cache;
1185 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001186 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1187 {
1188 cache_info->methods.destroy_pixel_handler(image);
1189 return;
1190 }
cristy2036f5c2010-09-19 21:18:17 +00001191 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001192}
1193
1194/*
1195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1196% %
1197% %
1198% %
1199+ D e s t r o y P i x e l C a c h e %
1200% %
1201% %
1202% %
1203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1204%
1205% DestroyPixelCache() deallocates memory associated with the pixel cache.
1206%
1207% The format of the DestroyPixelCache() method is:
1208%
1209% Cache DestroyPixelCache(Cache cache)
1210%
1211% A description of each parameter follows:
1212%
1213% o cache: the pixel cache.
1214%
1215*/
1216
1217static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1218{
1219 switch (cache_info->type)
1220 {
1221 case MemoryCache:
1222 {
1223 if (cache_info->mapped == MagickFalse)
cristy9dd0b6f2012-08-01 14:38:43 +00001224 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
cristy3ed852e2009-09-05 21:47:34 +00001225 cache_info->pixels);
1226 else
cristy4c08aed2011-07-01 19:47:50 +00001227 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001228 (size_t) cache_info->length);
1229 RelinquishMagickResource(MemoryResource,cache_info->length);
1230 break;
1231 }
1232 case MapCache:
1233 {
cristy4c08aed2011-07-01 19:47:50 +00001234 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001235 cache_info->length);
1236 RelinquishMagickResource(MapResource,cache_info->length);
1237 }
1238 case DiskCache:
1239 {
1240 if (cache_info->file != -1)
1241 (void) ClosePixelCacheOnDisk(cache_info);
1242 RelinquishMagickResource(DiskResource,cache_info->length);
1243 break;
1244 }
1245 default:
1246 break;
1247 }
1248 cache_info->type=UndefinedCache;
1249 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001250 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001251}
1252
cristya6577ff2011-09-02 19:54:26 +00001253MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001254{
1255 CacheInfo
1256 *cache_info;
1257
cristy3ed852e2009-09-05 21:47:34 +00001258 assert(cache != (Cache) NULL);
1259 cache_info=(CacheInfo *) cache;
1260 assert(cache_info->signature == MagickSignature);
1261 if (cache_info->debug != MagickFalse)
1262 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1263 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001264 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001265 cache_info->reference_count--;
1266 if (cache_info->reference_count != 0)
1267 {
cristyf84a1932010-01-03 18:00:18 +00001268 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001269 return((Cache) NULL);
1270 }
cristyf84a1932010-01-03 18:00:18 +00001271 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001272 if (cache_info->debug != MagickFalse)
1273 {
1274 char
1275 message[MaxTextExtent];
1276
cristyb51dff52011-05-19 16:55:47 +00001277 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001278 cache_info->filename);
1279 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1280 }
cristyc2e1bdd2009-09-10 23:43:34 +00001281 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1282 (cache_info->type != DiskCache)))
1283 RelinquishPixelCachePixels(cache_info);
1284 else
1285 {
1286 RelinquishPixelCachePixels(cache_info);
1287 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1288 }
cristy3ed852e2009-09-05 21:47:34 +00001289 *cache_info->cache_filename='\0';
1290 if (cache_info->nexus_info != (NexusInfo **) NULL)
1291 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1292 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001293 if (cache_info->random_info != (RandomInfo *) NULL)
1294 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001295 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1296 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1297 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1298 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001299 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001300 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001301 cache=(Cache) NULL;
1302 return(cache);
1303}
1304
1305/*
1306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307% %
1308% %
1309% %
1310+ D e s t r o y P i x e l C a c h e N e x u s %
1311% %
1312% %
1313% %
1314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1315%
1316% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1317%
1318% The format of the DestroyPixelCacheNexus() method is:
1319%
1320% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001321% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001322%
1323% A description of each parameter follows:
1324%
1325% o nexus_info: the nexus to destroy.
1326%
1327% o number_threads: the number of nexus threads.
1328%
1329*/
1330
1331static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1332{
1333 if (nexus_info->mapped == MagickFalse)
cristy9dd0b6f2012-08-01 14:38:43 +00001334 (void) RelinquishAlignedMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001335 else
1336 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001337 nexus_info->cache=(Quantum *) NULL;
1338 nexus_info->pixels=(Quantum *) NULL;
1339 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001340 nexus_info->length=0;
1341 nexus_info->mapped=MagickFalse;
1342}
1343
cristya6577ff2011-09-02 19:54:26 +00001344MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001345 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001346{
cristybb503372010-05-27 20:51:26 +00001347 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001348 i;
1349
1350 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001351 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001352 {
cristy4c08aed2011-07-01 19:47:50 +00001353 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001354 RelinquishCacheNexusPixels(nexus_info[i]);
1355 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001356 }
cristye5f87c82012-02-14 12:44:17 +00001357 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001358 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001359 return(nexus_info);
1360}
1361
1362/*
1363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364% %
1365% %
1366% %
cristy4c08aed2011-07-01 19:47:50 +00001367% G e t A u t h e n t i c M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00001368% %
1369% %
1370% %
1371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372%
cristy4c08aed2011-07-01 19:47:50 +00001373% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1374% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1375% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001376%
cristy4c08aed2011-07-01 19:47:50 +00001377% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001378%
cristy4c08aed2011-07-01 19:47:50 +00001379% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001380%
1381% A description of each parameter follows:
1382%
1383% o image: the image.
1384%
1385*/
cristy4c08aed2011-07-01 19:47:50 +00001386MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001387{
1388 CacheInfo
1389 *cache_info;
1390
cristy5c9e6f22010-09-17 17:31:01 +00001391 const int
1392 id = GetOpenMPThreadId();
1393
cristy4c08aed2011-07-01 19:47:50 +00001394 void
1395 *metacontent;
1396
cristye7cc7cf2010-09-21 13:26:47 +00001397 assert(image != (const Image *) NULL);
1398 assert(image->signature == MagickSignature);
1399 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001400 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001401 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001402 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1403 (GetAuthenticMetacontentFromHandler) NULL)
1404 {
1405 metacontent=cache_info->methods.
1406 get_authentic_metacontent_from_handler(image);
1407 return(metacontent);
1408 }
cristy6ebe97c2010-07-03 01:17:28 +00001409 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001410 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1411 cache_info->nexus_info[id]);
1412 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001413}
1414
1415/*
1416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1417% %
1418% %
1419% %
cristy4c08aed2011-07-01 19:47:50 +00001420+ G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00001421% %
1422% %
1423% %
1424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1425%
cristy4c08aed2011-07-01 19:47:50 +00001426% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1427% with the last call to QueueAuthenticPixelsCache() or
1428% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001429%
cristy4c08aed2011-07-01 19:47:50 +00001430% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001431%
cristy4c08aed2011-07-01 19:47:50 +00001432% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001433%
1434% A description of each parameter follows:
1435%
1436% o image: the image.
1437%
1438*/
cristy4c08aed2011-07-01 19:47:50 +00001439static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001440{
1441 CacheInfo
1442 *cache_info;
1443
cristy2036f5c2010-09-19 21:18:17 +00001444 const int
1445 id = GetOpenMPThreadId();
1446
cristy4c08aed2011-07-01 19:47:50 +00001447 void
1448 *metacontent;
1449
cristy3ed852e2009-09-05 21:47:34 +00001450 assert(image != (const Image *) NULL);
1451 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001452 assert(image->cache != (Cache) NULL);
1453 cache_info=(CacheInfo *) image->cache;
1454 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001455 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001456 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1457 cache_info->nexus_info[id]);
1458 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001459}
1460
1461/*
1462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1463% %
1464% %
1465% %
1466+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1467% %
1468% %
1469% %
1470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1471%
1472% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1473% disk pixel cache as defined by the geometry parameters. A pointer to the
1474% pixels is returned if the pixels are transferred, otherwise a NULL is
1475% returned.
1476%
1477% The format of the GetAuthenticPixelCacheNexus() method is:
1478%
cristy4c08aed2011-07-01 19:47:50 +00001479% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001480% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001481% NexusInfo *nexus_info,ExceptionInfo *exception)
1482%
1483% A description of each parameter follows:
1484%
1485% o image: the image.
1486%
1487% o x,y,columns,rows: These values define the perimeter of a region of
1488% pixels.
1489%
1490% o nexus_info: the cache nexus to return.
1491%
1492% o exception: return any errors or warnings in this structure.
1493%
1494*/
1495
cristy7f69b802012-05-08 16:39:59 +00001496static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001497 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001498{
cristy4c08aed2011-07-01 19:47:50 +00001499 MagickBooleanType
1500 status;
1501
cristy3ed852e2009-09-05 21:47:34 +00001502 MagickOffsetType
1503 offset;
1504
cristy73724512010-04-12 14:43:14 +00001505 if (cache_info->type == PingCache)
1506 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001507 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1508 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001509 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001510 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001511 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001512}
1513
cristya6577ff2011-09-02 19:54:26 +00001514MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001515 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001516 NexusInfo *nexus_info,ExceptionInfo *exception)
1517{
1518 CacheInfo
1519 *cache_info;
1520
cristy4c08aed2011-07-01 19:47:50 +00001521 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001522 *q;
cristy3ed852e2009-09-05 21:47:34 +00001523
1524 /*
1525 Transfer pixels from the cache.
1526 */
1527 assert(image != (Image *) NULL);
1528 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001529 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1530 exception);
cristyacd2ed22011-08-30 01:44:23 +00001531 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001532 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001533 cache_info=(CacheInfo *) image->cache;
1534 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001535 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001536 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001537 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001538 return((Quantum *) NULL);
1539 if (cache_info->metacontent_extent != 0)
1540 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1541 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001542 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001543}
1544
1545/*
1546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547% %
1548% %
1549% %
1550+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1551% %
1552% %
1553% %
1554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555%
1556% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1557% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1558%
1559% The format of the GetAuthenticPixelsFromCache() method is:
1560%
cristy4c08aed2011-07-01 19:47:50 +00001561% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001562%
1563% A description of each parameter follows:
1564%
1565% o image: the image.
1566%
1567*/
cristy4c08aed2011-07-01 19:47:50 +00001568static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001569{
1570 CacheInfo
1571 *cache_info;
1572
cristy5c9e6f22010-09-17 17:31:01 +00001573 const int
1574 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001575
cristye7cc7cf2010-09-21 13:26:47 +00001576 assert(image != (const Image *) NULL);
1577 assert(image->signature == MagickSignature);
1578 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001579 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001580 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001581 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001582 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001583}
1584
1585/*
1586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587% %
1588% %
1589% %
1590% G e t A u t h e n t i c P i x e l Q u e u e %
1591% %
1592% %
1593% %
1594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595%
cristy4c08aed2011-07-01 19:47:50 +00001596% GetAuthenticPixelQueue() returns the authentic pixels associated
1597% corresponding with the last call to QueueAuthenticPixels() or
1598% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001599%
1600% The format of the GetAuthenticPixelQueue() method is:
1601%
cristy4c08aed2011-07-01 19:47:50 +00001602% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001603%
1604% A description of each parameter follows:
1605%
1606% o image: the image.
1607%
1608*/
cristy4c08aed2011-07-01 19:47:50 +00001609MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001610{
1611 CacheInfo
1612 *cache_info;
1613
cristy2036f5c2010-09-19 21:18:17 +00001614 const int
1615 id = GetOpenMPThreadId();
1616
cristy3ed852e2009-09-05 21:47:34 +00001617 assert(image != (const Image *) NULL);
1618 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001619 assert(image->cache != (Cache) NULL);
1620 cache_info=(CacheInfo *) image->cache;
1621 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001622 if (cache_info->methods.get_authentic_pixels_from_handler !=
1623 (GetAuthenticPixelsFromHandler) NULL)
1624 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001625 assert(id < (int) cache_info->number_threads);
1626 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001627}
1628
1629/*
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631% %
1632% %
1633% %
1634% G e t A u t h e n t i c P i x e l s %
1635% %
1636% %
cristy4c08aed2011-07-01 19:47:50 +00001637% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001638%
1639% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001640% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001641% representing the region is returned, otherwise NULL is returned.
1642%
1643% The returned pointer may point to a temporary working copy of the pixels
1644% or it may point to the original pixels in memory. Performance is maximized
1645% if the selected region is part of one row, or one or more full rows, since
1646% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001647% if the image is in memory, or in a memory-mapped file. The returned pointer
1648% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001649%
1650% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001651% Quantum. If the image has corresponding metacontent,call
1652% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1653% meta-content corresponding to the region. Once the Quantum array has
1654% been updated, the changes must be saved back to the underlying image using
1655% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001656%
1657% The format of the GetAuthenticPixels() method is:
1658%
cristy4c08aed2011-07-01 19:47:50 +00001659% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001660% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001661% ExceptionInfo *exception)
1662%
1663% A description of each parameter follows:
1664%
1665% o image: the image.
1666%
1667% o x,y,columns,rows: These values define the perimeter of a region of
1668% pixels.
1669%
1670% o exception: return any errors or warnings in this structure.
1671%
1672*/
cristy4c08aed2011-07-01 19:47:50 +00001673MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001674 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001675 ExceptionInfo *exception)
1676{
1677 CacheInfo
1678 *cache_info;
1679
cristy2036f5c2010-09-19 21:18:17 +00001680 const int
1681 id = GetOpenMPThreadId();
1682
cristy4c08aed2011-07-01 19:47:50 +00001683 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001684 *q;
cristy4c08aed2011-07-01 19:47:50 +00001685
cristy3ed852e2009-09-05 21:47:34 +00001686 assert(image != (Image *) NULL);
1687 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001688 assert(image->cache != (Cache) NULL);
1689 cache_info=(CacheInfo *) image->cache;
1690 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001691 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001692 (GetAuthenticPixelsHandler) NULL)
1693 {
cristyacd2ed22011-08-30 01:44:23 +00001694 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1695 exception);
1696 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001697 }
cristy2036f5c2010-09-19 21:18:17 +00001698 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001699 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001700 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001701 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001702}
1703
1704/*
1705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1706% %
1707% %
1708% %
1709+ G e t A u t h e n t i c P i x e l s C a c h e %
1710% %
1711% %
1712% %
1713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1714%
1715% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1716% as defined by the geometry parameters. A pointer to the pixels is returned
1717% if the pixels are transferred, otherwise a NULL is returned.
1718%
1719% The format of the GetAuthenticPixelsCache() method is:
1720%
cristy4c08aed2011-07-01 19:47:50 +00001721% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001722% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001723% ExceptionInfo *exception)
1724%
1725% A description of each parameter follows:
1726%
1727% o image: the image.
1728%
1729% o x,y,columns,rows: These values define the perimeter of a region of
1730% pixels.
1731%
1732% o exception: return any errors or warnings in this structure.
1733%
1734*/
cristy4c08aed2011-07-01 19:47:50 +00001735static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001736 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001737 ExceptionInfo *exception)
1738{
1739 CacheInfo
1740 *cache_info;
1741
cristy5c9e6f22010-09-17 17:31:01 +00001742 const int
1743 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001744
cristy4c08aed2011-07-01 19:47:50 +00001745 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001746 *q;
cristy4c08aed2011-07-01 19:47:50 +00001747
cristye7cc7cf2010-09-21 13:26:47 +00001748 assert(image != (const Image *) NULL);
1749 assert(image->signature == MagickSignature);
1750 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001751 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001752 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001753 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001754 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001755 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001756 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001757 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001758 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001759}
1760
1761/*
1762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763% %
1764% %
1765% %
1766+ G e t I m a g e E x t e n t %
1767% %
1768% %
1769% %
1770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1771%
cristy4c08aed2011-07-01 19:47:50 +00001772% GetImageExtent() returns the extent of the pixels associated corresponding
1773% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001774%
1775% The format of the GetImageExtent() method is:
1776%
1777% MagickSizeType GetImageExtent(const Image *image)
1778%
1779% A description of each parameter follows:
1780%
1781% o image: the image.
1782%
1783*/
1784MagickExport MagickSizeType GetImageExtent(const Image *image)
1785{
1786 CacheInfo
1787 *cache_info;
1788
cristy5c9e6f22010-09-17 17:31:01 +00001789 const int
1790 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001791
cristy3ed852e2009-09-05 21:47:34 +00001792 assert(image != (Image *) NULL);
1793 assert(image->signature == MagickSignature);
1794 if (image->debug != MagickFalse)
1795 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1796 assert(image->cache != (Cache) NULL);
1797 cache_info=(CacheInfo *) image->cache;
1798 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001799 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001800 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001801}
1802
1803/*
1804%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1805% %
1806% %
1807% %
1808+ G e t I m a g e P i x e l C a c h e %
1809% %
1810% %
1811% %
1812%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1813%
1814% GetImagePixelCache() ensures that there is only a single reference to the
1815% pixel cache to be modified, updating the provided cache pointer to point to
1816% a clone of the original pixel cache if necessary.
1817%
1818% The format of the GetImagePixelCache method is:
1819%
1820% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1821% ExceptionInfo *exception)
1822%
1823% A description of each parameter follows:
1824%
1825% o image: the image.
1826%
1827% o clone: any value other than MagickFalse clones the cache pixels.
1828%
1829% o exception: return any errors or warnings in this structure.
1830%
1831*/
cristyaf894d72011-08-06 23:03:10 +00001832
cristyf1832792012-05-08 18:38:18 +00001833static inline MagickBooleanType ValidatePixelCacheMorphology(
1834 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001835{
cristyf1832792012-05-08 18:38:18 +00001836 const CacheInfo
1837 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001838
cristyf1832792012-05-08 18:38:18 +00001839 const PixelChannelMap
1840 *restrict p,
1841 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001842
cristy3ed852e2009-09-05 21:47:34 +00001843 /*
1844 Does the image match the pixel cache morphology?
1845 */
1846 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001847 p=image->channel_map;
1848 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001849 if ((image->storage_class != cache_info->storage_class) ||
1850 (image->colorspace != cache_info->colorspace) ||
cristy8a46d822012-08-28 23:32:39 +00001851 (image->alpha_trait != cache_info->alpha_trait) ||
cristy183a5c72012-01-30 01:40:35 +00001852 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001853 (image->columns != cache_info->columns) ||
1854 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001855 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001856 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001857 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001858 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001859 return(MagickFalse);
1860 return(MagickTrue);
1861}
1862
cristycd01fae2011-08-06 23:52:42 +00001863static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1864 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001865{
1866 CacheInfo
1867 *cache_info;
1868
cristy3ed852e2009-09-05 21:47:34 +00001869 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001870 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001871 status;
1872
cristy50a10922010-02-15 18:35:25 +00001873 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001874 cpu_throttle = 0,
1875 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001876 time_limit = 0;
1877
cristy1ea34962010-07-01 19:49:21 +00001878 static time_t
cristy208b1002011-08-07 18:51:50 +00001879 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001880
cristyc4f9f132010-03-04 18:50:01 +00001881 status=MagickTrue;
1882 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001883 if (cpu_throttle == 0)
1884 {
1885 char
1886 *limit;
1887
1888 /*
1889 Set CPU throttle in milleseconds.
1890 */
1891 cpu_throttle=MagickResourceInfinity;
1892 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1893 if (limit == (char *) NULL)
1894 limit=GetPolicyValue("throttle");
1895 if (limit != (char *) NULL)
1896 {
1897 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1898 limit=DestroyString(limit);
1899 }
1900 }
1901 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1902 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001903 if (time_limit == 0)
1904 {
cristy6ebe97c2010-07-03 01:17:28 +00001905 /*
cristy3a8401e2012-10-29 22:01:37 +00001906 Set the expire time in seconds.
cristy6ebe97c2010-07-03 01:17:28 +00001907 */
cristy1ea34962010-07-01 19:49:21 +00001908 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001909 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001910 }
1911 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001912 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001913 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001914 assert(image->cache != (Cache) NULL);
1915 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001916 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001917 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001918 {
cristyceb55ee2010-11-06 16:05:49 +00001919 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001920 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001921 {
cristyceb55ee2010-11-06 16:05:49 +00001922 CacheInfo
1923 *clone_info;
1924
cristya28c61e2012-10-29 22:03:42 +00001925 Image
1926 clone_image;
1927
cristyceb55ee2010-11-06 16:05:49 +00001928 /*
1929 Clone pixel cache.
1930 */
1931 clone_image=(*image);
1932 clone_image.semaphore=AllocateSemaphoreInfo();
1933 clone_image.reference_count=1;
1934 clone_image.cache=ClonePixelCache(cache_info);
1935 clone_info=(CacheInfo *) clone_image.cache;
1936 status=OpenPixelCache(&clone_image,IOMode,exception);
1937 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001938 {
cristy5a7fbfb2010-11-06 16:10:59 +00001939 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001940 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001941 if (status != MagickFalse)
1942 {
cristyceb55ee2010-11-06 16:05:49 +00001943 destroy=MagickTrue;
1944 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001945 }
1946 }
cristyceb55ee2010-11-06 16:05:49 +00001947 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001948 }
cristyceb55ee2010-11-06 16:05:49 +00001949 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001950 }
cristy4320e0e2009-09-10 15:00:08 +00001951 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001952 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001953 if (status != MagickFalse)
1954 {
1955 /*
1956 Ensure the image matches the pixel cache morphology.
1957 */
1958 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001959 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001960 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001961 {
1962 status=OpenPixelCache(image,IOMode,exception);
1963 cache_info=(CacheInfo *) image->cache;
1964 if (cache_info->type == DiskCache)
1965 (void) ClosePixelCacheOnDisk(cache_info);
1966 }
cristy3ed852e2009-09-05 21:47:34 +00001967 }
cristyf84a1932010-01-03 18:00:18 +00001968 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001969 if (status == MagickFalse)
1970 return((Cache) NULL);
1971 return(image->cache);
1972}
1973
1974/*
1975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1976% %
1977% %
1978% %
cristyce1fe792012-05-16 15:58:37 +00001979+ G e t I m a g e P i x e l C a c h e T y p e %
1980% %
1981% %
1982% %
1983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1984%
1985% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1986% DiskCache, MemoryCache, MapCache, or PingCache.
1987%
1988% The format of the GetImagePixelCacheType() method is:
1989%
cristy5bef4cd2012-05-17 18:08:56 +00001990% CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001991%
1992% A description of each parameter follows:
1993%
1994% o image: the image.
1995%
1996*/
cristy5bef4cd2012-05-17 18:08:56 +00001997MagickExport CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001998{
cristy238287d2012-05-17 18:16:56 +00001999 CacheInfo
2000 *cache_info;
2001
2002 assert(image != (Image *) NULL);
2003 assert(image->signature == MagickSignature);
2004 assert(image->cache != (Cache) NULL);
2005 cache_info=(CacheInfo *) image->cache;
2006 assert(cache_info->signature == MagickSignature);
2007 return(cache_info->type);
cristyce1fe792012-05-16 15:58:37 +00002008}
2009
2010/*
2011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2012% %
2013% %
2014% %
cristy3ed852e2009-09-05 21:47:34 +00002015% G e t O n e A u t h e n t i c P i x e l %
2016% %
2017% %
2018% %
2019%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2020%
2021% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2022% location. The image background color is returned if an error occurs.
2023%
2024% The format of the GetOneAuthenticPixel() method is:
2025%
cristybb503372010-05-27 20:51:26 +00002026% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002027% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002028%
2029% A description of each parameter follows:
2030%
2031% o image: the image.
2032%
2033% o x,y: These values define the location of the pixel to return.
2034%
2035% o pixel: return a pixel at the specified (x,y) location.
2036%
2037% o exception: return any errors or warnings in this structure.
2038%
2039*/
cristyacbbb7c2010-06-30 18:56:48 +00002040MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002041 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002042{
2043 CacheInfo
2044 *cache_info;
2045
cristy4c08aed2011-07-01 19:47:50 +00002046 register Quantum
2047 *q;
cristy2036f5c2010-09-19 21:18:17 +00002048
cristy2ed42f62011-10-02 19:49:57 +00002049 register ssize_t
2050 i;
2051
cristy3ed852e2009-09-05 21:47:34 +00002052 assert(image != (Image *) NULL);
2053 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002054 assert(image->cache != (Cache) NULL);
2055 cache_info=(CacheInfo *) image->cache;
2056 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002057 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002058 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2059 (GetOneAuthenticPixelFromHandler) NULL)
2060 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2061 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002062 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2063 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002064 {
cristy9e0719b2011-12-29 03:45:45 +00002065 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2066 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2067 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2068 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2069 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002070 return(MagickFalse);
2071 }
2072 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2073 {
2074 PixelChannel
2075 channel;
2076
cristycf1296e2012-08-26 23:40:49 +00002077 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002078 pixel[channel]=q[i];
2079 }
cristy2036f5c2010-09-19 21:18:17 +00002080 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002081}
2082
2083/*
2084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2085% %
2086% %
2087% %
2088+ G e t O n e A u t h e n t i c P i x e l F r o m C a c h e %
2089% %
2090% %
2091% %
2092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2093%
2094% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2095% location. The image background color is returned if an error occurs.
2096%
2097% The format of the GetOneAuthenticPixelFromCache() method is:
2098%
2099% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002100% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002101% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002102%
2103% A description of each parameter follows:
2104%
2105% o image: the image.
2106%
2107% o x,y: These values define the location of the pixel to return.
2108%
2109% o pixel: return a pixel at the specified (x,y) location.
2110%
2111% o exception: return any errors or warnings in this structure.
2112%
2113*/
2114static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002115 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002116{
cristy098f78c2010-09-23 17:28:44 +00002117 CacheInfo
2118 *cache_info;
2119
2120 const int
2121 id = GetOpenMPThreadId();
2122
cristy4c08aed2011-07-01 19:47:50 +00002123 register Quantum
2124 *q;
cristy3ed852e2009-09-05 21:47:34 +00002125
cristy2ed42f62011-10-02 19:49:57 +00002126 register ssize_t
2127 i;
2128
cristy0158a4b2010-09-20 13:59:45 +00002129 assert(image != (const Image *) NULL);
2130 assert(image->signature == MagickSignature);
2131 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002132 cache_info=(CacheInfo *) image->cache;
2133 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002134 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002135 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002136 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2137 exception);
2138 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002139 {
cristy9e0719b2011-12-29 03:45:45 +00002140 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2141 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2142 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2143 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2144 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002145 return(MagickFalse);
2146 }
2147 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2148 {
2149 PixelChannel
2150 channel;
2151
cristycf1296e2012-08-26 23:40:49 +00002152 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002153 pixel[channel]=q[i];
2154 }
cristy3ed852e2009-09-05 21:47:34 +00002155 return(MagickTrue);
2156}
2157
2158/*
2159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2160% %
2161% %
2162% %
cristy3ed852e2009-09-05 21:47:34 +00002163% G e t O n e V i r t u a l P i x e l %
2164% %
2165% %
2166% %
2167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2168%
2169% GetOneVirtualPixel() returns a single virtual pixel at the specified
2170% (x,y) location. The image background color is returned if an error occurs.
2171% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2172%
2173% The format of the GetOneVirtualPixel() method is:
2174%
cristybb503372010-05-27 20:51:26 +00002175% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002176% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002177%
2178% A description of each parameter follows:
2179%
2180% o image: the image.
2181%
2182% o x,y: These values define the location of the pixel to return.
2183%
2184% o pixel: return a pixel at the specified (x,y) location.
2185%
2186% o exception: return any errors or warnings in this structure.
2187%
2188*/
2189MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002190 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002191{
cristy3ed852e2009-09-05 21:47:34 +00002192 CacheInfo
2193 *cache_info;
2194
cristy0158a4b2010-09-20 13:59:45 +00002195 const int
2196 id = GetOpenMPThreadId();
2197
cristy4c08aed2011-07-01 19:47:50 +00002198 const Quantum
2199 *p;
cristy2036f5c2010-09-19 21:18:17 +00002200
cristy2ed42f62011-10-02 19:49:57 +00002201 register ssize_t
2202 i;
2203
cristy3ed852e2009-09-05 21:47:34 +00002204 assert(image != (const Image *) NULL);
2205 assert(image->signature == MagickSignature);
2206 assert(image->cache != (Cache) NULL);
2207 cache_info=(CacheInfo *) image->cache;
2208 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002209 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002210 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2211 (GetOneVirtualPixelFromHandler) NULL)
2212 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2213 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002214 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002215 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002216 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002217 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002218 {
cristy9e0719b2011-12-29 03:45:45 +00002219 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2220 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2221 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2222 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2223 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002224 return(MagickFalse);
2225 }
2226 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2227 {
2228 PixelChannel
2229 channel;
2230
cristycf1296e2012-08-26 23:40:49 +00002231 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002232 pixel[channel]=p[i];
2233 }
cristy2036f5c2010-09-19 21:18:17 +00002234 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002235}
2236
2237/*
2238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2239% %
2240% %
2241% %
2242+ G e t O n e V i r t u a l P i x e l F r o m C a c h e %
2243% %
2244% %
2245% %
2246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247%
2248% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2249% specified (x,y) location. The image background color is returned if an
2250% error occurs.
2251%
2252% The format of the GetOneVirtualPixelFromCache() method is:
2253%
2254% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002255% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002256% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002257%
2258% A description of each parameter follows:
2259%
2260% o image: the image.
2261%
2262% o virtual_pixel_method: the virtual pixel method.
2263%
2264% o x,y: These values define the location of the pixel to return.
2265%
2266% o pixel: return a pixel at the specified (x,y) location.
2267%
2268% o exception: return any errors or warnings in this structure.
2269%
2270*/
2271static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002272 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002273 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002274{
cristy0158a4b2010-09-20 13:59:45 +00002275 CacheInfo
2276 *cache_info;
2277
2278 const int
2279 id = GetOpenMPThreadId();
2280
cristy4c08aed2011-07-01 19:47:50 +00002281 const Quantum
2282 *p;
cristy3ed852e2009-09-05 21:47:34 +00002283
cristy2ed42f62011-10-02 19:49:57 +00002284 register ssize_t
2285 i;
2286
cristye7cc7cf2010-09-21 13:26:47 +00002287 assert(image != (const Image *) NULL);
2288 assert(image->signature == MagickSignature);
2289 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002290 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002291 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002292 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002293 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002294 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002295 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002296 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002297 {
cristy9e0719b2011-12-29 03:45:45 +00002298 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2299 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2300 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2301 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2302 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002303 return(MagickFalse);
2304 }
2305 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2306 {
2307 PixelChannel
2308 channel;
2309
cristycf1296e2012-08-26 23:40:49 +00002310 channel=GetPixelChannelChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002311 pixel[channel]=p[i];
2312 }
cristy3ed852e2009-09-05 21:47:34 +00002313 return(MagickTrue);
2314}
2315
2316/*
2317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2318% %
2319% %
2320% %
cristy3aa93752011-12-18 15:54:24 +00002321% G e t O n e V i r t u a l P i x e l I n f o %
2322% %
2323% %
2324% %
2325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2326%
2327% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2328% location. The image background color is returned if an error occurs. If
2329% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2330%
2331% The format of the GetOneVirtualPixelInfo() method is:
2332%
2333% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2334% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2335% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2336%
2337% A description of each parameter follows:
2338%
2339% o image: the image.
2340%
2341% o virtual_pixel_method: the virtual pixel method.
2342%
2343% o x,y: these values define the location of the pixel to return.
2344%
2345% o pixel: return a pixel at the specified (x,y) location.
2346%
2347% o exception: return any errors or warnings in this structure.
2348%
2349*/
2350MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2351 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2352 PixelInfo *pixel,ExceptionInfo *exception)
2353{
2354 CacheInfo
2355 *cache_info;
2356
2357 const int
2358 id = GetOpenMPThreadId();
2359
2360 register const Quantum
2361 *p;
2362
2363 assert(image != (const Image *) NULL);
2364 assert(image->signature == MagickSignature);
2365 assert(image->cache != (Cache) NULL);
2366 cache_info=(CacheInfo *) image->cache;
2367 assert(cache_info->signature == MagickSignature);
2368 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002369 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002370 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2371 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002372 if (p == (const Quantum *) NULL)
2373 return(MagickFalse);
2374 GetPixelInfoPixel(image,p,pixel);
2375 return(MagickTrue);
2376}
2377
2378/*
2379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380% %
2381% %
2382% %
cristy3ed852e2009-09-05 21:47:34 +00002383+ G e t P i x e l C a c h e C o l o r s p a c e %
2384% %
2385% %
2386% %
2387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388%
2389% GetPixelCacheColorspace() returns the class type of the pixel cache.
2390%
2391% The format of the GetPixelCacheColorspace() method is:
2392%
2393% Colorspace GetPixelCacheColorspace(Cache cache)
2394%
2395% A description of each parameter follows:
2396%
2397% o cache: the pixel cache.
2398%
2399*/
cristya6577ff2011-09-02 19:54:26 +00002400MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002401{
2402 CacheInfo
2403 *cache_info;
2404
2405 assert(cache != (Cache) NULL);
2406 cache_info=(CacheInfo *) cache;
2407 assert(cache_info->signature == MagickSignature);
2408 if (cache_info->debug != MagickFalse)
2409 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2410 cache_info->filename);
2411 return(cache_info->colorspace);
2412}
2413
2414/*
2415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2416% %
2417% %
2418% %
2419+ G e t P i x e l C a c h e M e t h o d s %
2420% %
2421% %
2422% %
2423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2424%
2425% GetPixelCacheMethods() initializes the CacheMethods structure.
2426%
2427% The format of the GetPixelCacheMethods() method is:
2428%
2429% void GetPixelCacheMethods(CacheMethods *cache_methods)
2430%
2431% A description of each parameter follows:
2432%
2433% o cache_methods: Specifies a pointer to a CacheMethods structure.
2434%
2435*/
cristya6577ff2011-09-02 19:54:26 +00002436MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002437{
2438 assert(cache_methods != (CacheMethods *) NULL);
2439 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2440 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2441 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002442 cache_methods->get_virtual_metacontent_from_handler=
2443 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002444 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2445 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002446 cache_methods->get_authentic_metacontent_from_handler=
2447 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002448 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2449 cache_methods->get_one_authentic_pixel_from_handler=
2450 GetOneAuthenticPixelFromCache;
2451 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2452 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2453 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2454}
2455
2456/*
2457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2458% %
2459% %
2460% %
2461+ G e t P i x e l C a c h e N e x u s E x t e n t %
2462% %
2463% %
2464% %
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466%
cristy4c08aed2011-07-01 19:47:50 +00002467% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2468% corresponding with the last call to SetPixelCacheNexusPixels() or
2469% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002470%
2471% The format of the GetPixelCacheNexusExtent() method is:
2472%
2473% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2474% NexusInfo *nexus_info)
2475%
2476% A description of each parameter follows:
2477%
2478% o nexus_info: the nexus info.
2479%
2480*/
cristya6577ff2011-09-02 19:54:26 +00002481MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002482 NexusInfo *nexus_info)
2483{
2484 CacheInfo
2485 *cache_info;
2486
2487 MagickSizeType
2488 extent;
2489
cristy9f027d12011-09-21 01:17:17 +00002490 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002491 cache_info=(CacheInfo *) cache;
2492 assert(cache_info->signature == MagickSignature);
2493 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2494 if (extent == 0)
2495 return((MagickSizeType) cache_info->columns*cache_info->rows);
2496 return(extent);
2497}
2498
2499/*
2500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501% %
2502% %
2503% %
cristy4c08aed2011-07-01 19:47:50 +00002504+ G e t P i x e l C a c h e N e x u s M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002505% %
2506% %
2507% %
2508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2509%
cristy4c08aed2011-07-01 19:47:50 +00002510% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2511% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002512%
cristy4c08aed2011-07-01 19:47:50 +00002513% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002514%
cristy4c08aed2011-07-01 19:47:50 +00002515% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002516% NexusInfo *nexus_info)
2517%
2518% A description of each parameter follows:
2519%
2520% o cache: the pixel cache.
2521%
cristy4c08aed2011-07-01 19:47:50 +00002522% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002523%
2524*/
cristya6577ff2011-09-02 19:54:26 +00002525MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002526 NexusInfo *nexus_info)
2527{
2528 CacheInfo
2529 *cache_info;
2530
cristy9f027d12011-09-21 01:17:17 +00002531 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002532 cache_info=(CacheInfo *) cache;
2533 assert(cache_info->signature == MagickSignature);
2534 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002535 return((void *) NULL);
2536 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002537}
2538
2539/*
2540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2541% %
2542% %
2543% %
2544+ G e t P i x e l C a c h e N e x u s P i x e l s %
2545% %
2546% %
2547% %
2548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549%
2550% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2551% cache nexus.
2552%
2553% The format of the GetPixelCacheNexusPixels() method is:
2554%
cristy4c08aed2011-07-01 19:47:50 +00002555% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002556% NexusInfo *nexus_info)
2557%
2558% A description of each parameter follows:
2559%
2560% o cache: the pixel cache.
2561%
2562% o nexus_info: the cache nexus to return the pixels.
2563%
2564*/
cristya6577ff2011-09-02 19:54:26 +00002565MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002566 NexusInfo *nexus_info)
2567{
2568 CacheInfo
2569 *cache_info;
2570
cristy9f027d12011-09-21 01:17:17 +00002571 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002572 cache_info=(CacheInfo *) cache;
2573 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002574 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002575 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002576 return(nexus_info->pixels);
2577}
2578
2579/*
2580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2581% %
2582% %
2583% %
cristy056ba772010-01-02 23:33:54 +00002584+ G e t P i x e l C a c h e P i x e l s %
2585% %
2586% %
2587% %
2588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2589%
2590% GetPixelCachePixels() returns the pixels associated with the specified image.
2591%
2592% The format of the GetPixelCachePixels() method is:
2593%
cristyf84a1932010-01-03 18:00:18 +00002594% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2595% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002596%
2597% A description of each parameter follows:
2598%
2599% o image: the image.
2600%
2601% o length: the pixel cache length.
2602%
cristyf84a1932010-01-03 18:00:18 +00002603% o exception: return any errors or warnings in this structure.
2604%
cristy056ba772010-01-02 23:33:54 +00002605*/
cristyd1dd6e42011-09-04 01:46:08 +00002606MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002607 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002608{
2609 CacheInfo
2610 *cache_info;
2611
2612 assert(image != (const Image *) NULL);
2613 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002614 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002615 assert(length != (MagickSizeType *) NULL);
2616 assert(exception != (ExceptionInfo *) NULL);
2617 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002618 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002619 assert(cache_info->signature == MagickSignature);
2620 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002621 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002622 return((void *) NULL);
2623 *length=cache_info->length;
2624 return((void *) cache_info->pixels);
2625}
2626
2627/*
2628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2629% %
2630% %
2631% %
cristyb32b90a2009-09-07 21:45:48 +00002632+ G e t P i x e l C a c h e S t o r a g e C l a s s %
cristy3ed852e2009-09-05 21:47:34 +00002633% %
2634% %
2635% %
2636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2637%
2638% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2639%
2640% The format of the GetPixelCacheStorageClass() method is:
2641%
2642% ClassType GetPixelCacheStorageClass(Cache cache)
2643%
2644% A description of each parameter follows:
2645%
2646% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2647%
2648% o cache: the pixel cache.
2649%
2650*/
cristya6577ff2011-09-02 19:54:26 +00002651MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002652{
2653 CacheInfo
2654 *cache_info;
2655
2656 assert(cache != (Cache) NULL);
2657 cache_info=(CacheInfo *) cache;
2658 assert(cache_info->signature == MagickSignature);
2659 if (cache_info->debug != MagickFalse)
2660 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2661 cache_info->filename);
2662 return(cache_info->storage_class);
2663}
2664
2665/*
2666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2667% %
2668% %
2669% %
cristyb32b90a2009-09-07 21:45:48 +00002670+ G e t P i x e l C a c h e T i l e S i z e %
2671% %
2672% %
2673% %
2674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675%
2676% GetPixelCacheTileSize() returns the pixel cache tile size.
2677%
2678% The format of the GetPixelCacheTileSize() method is:
2679%
cristybb503372010-05-27 20:51:26 +00002680% void GetPixelCacheTileSize(const Image *image,size_t *width,
2681% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002682%
2683% A description of each parameter follows:
2684%
2685% o image: the image.
2686%
2687% o width: the optimize cache tile width in pixels.
2688%
2689% o height: the optimize cache tile height in pixels.
2690%
2691*/
cristya6577ff2011-09-02 19:54:26 +00002692MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002693 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002694{
cristy4c08aed2011-07-01 19:47:50 +00002695 CacheInfo
2696 *cache_info;
2697
cristyb32b90a2009-09-07 21:45:48 +00002698 assert(image != (Image *) NULL);
2699 assert(image->signature == MagickSignature);
2700 if (image->debug != MagickFalse)
2701 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002702 cache_info=(CacheInfo *) image->cache;
2703 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002704 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristy238287d2012-05-17 18:16:56 +00002705 if (GetImagePixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002706 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002707 *height=(*width);
2708}
2709
2710/*
2711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2712% %
2713% %
2714% %
cristy3ed852e2009-09-05 21:47:34 +00002715+ G e t P i x e l C a c h e V i r t u a l M e t h o d %
2716% %
2717% %
2718% %
2719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2720%
2721% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2722% pixel cache. A virtual pixel is any pixel access that is outside the
2723% boundaries of the image cache.
2724%
2725% The format of the GetPixelCacheVirtualMethod() method is:
2726%
2727% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2728%
2729% A description of each parameter follows:
2730%
2731% o image: the image.
2732%
2733*/
cristyd1dd6e42011-09-04 01:46:08 +00002734MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002735{
2736 CacheInfo
2737 *cache_info;
2738
2739 assert(image != (Image *) NULL);
2740 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002741 assert(image->cache != (Cache) NULL);
2742 cache_info=(CacheInfo *) image->cache;
2743 assert(cache_info->signature == MagickSignature);
2744 return(cache_info->virtual_pixel_method);
2745}
2746
2747/*
2748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749% %
2750% %
2751% %
cristy4c08aed2011-07-01 19:47:50 +00002752+ G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00002753% %
2754% %
2755% %
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757%
cristy4c08aed2011-07-01 19:47:50 +00002758% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2759% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002760%
cristy4c08aed2011-07-01 19:47:50 +00002761% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002762%
cristy4c08aed2011-07-01 19:47:50 +00002763% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002764%
2765% A description of each parameter follows:
2766%
2767% o image: the image.
2768%
2769*/
cristy4c08aed2011-07-01 19:47:50 +00002770static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002771{
2772 CacheInfo
2773 *cache_info;
2774
cristy5c9e6f22010-09-17 17:31:01 +00002775 const int
2776 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002777
cristy4c08aed2011-07-01 19:47:50 +00002778 const void
2779 *metacontent;
2780
cristye7cc7cf2010-09-21 13:26:47 +00002781 assert(image != (const Image *) NULL);
2782 assert(image->signature == MagickSignature);
2783 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002784 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002785 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002786 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002787 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2788 cache_info->nexus_info[id]);
2789 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002790}
2791
2792/*
2793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2794% %
2795% %
2796% %
cristy4c08aed2011-07-01 19:47:50 +00002797+ G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00002798% %
2799% %
2800% %
2801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802%
cristy4c08aed2011-07-01 19:47:50 +00002803% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2804% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002805%
cristy4c08aed2011-07-01 19:47:50 +00002806% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002807%
cristy4c08aed2011-07-01 19:47:50 +00002808% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002809% NexusInfo *nexus_info)
2810%
2811% A description of each parameter follows:
2812%
2813% o cache: the pixel cache.
2814%
cristy4c08aed2011-07-01 19:47:50 +00002815% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002816%
2817*/
cristya6577ff2011-09-02 19:54:26 +00002818MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002819 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002820{
2821 CacheInfo
2822 *cache_info;
2823
cristye7cc7cf2010-09-21 13:26:47 +00002824 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002825 cache_info=(CacheInfo *) cache;
2826 assert(cache_info->signature == MagickSignature);
2827 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002828 return((void *) NULL);
2829 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002830}
2831
2832/*
2833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2834% %
2835% %
2836% %
cristy4c08aed2011-07-01 19:47:50 +00002837% G e t V i r t u a l M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002838% %
2839% %
2840% %
2841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2842%
cristy4c08aed2011-07-01 19:47:50 +00002843% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2844% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2845% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002846%
cristy4c08aed2011-07-01 19:47:50 +00002847% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002848%
cristy4c08aed2011-07-01 19:47:50 +00002849% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002850%
2851% A description of each parameter follows:
2852%
2853% o image: the image.
2854%
2855*/
cristy4c08aed2011-07-01 19:47:50 +00002856MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002857{
2858 CacheInfo
2859 *cache_info;
2860
cristy2036f5c2010-09-19 21:18:17 +00002861 const int
2862 id = GetOpenMPThreadId();
2863
cristy4c08aed2011-07-01 19:47:50 +00002864 const void
2865 *metacontent;
2866
cristy3ed852e2009-09-05 21:47:34 +00002867 assert(image != (const Image *) NULL);
2868 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002869 assert(image->cache != (Cache) NULL);
2870 cache_info=(CacheInfo *) image->cache;
2871 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002872 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002873 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002874 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002875 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002876 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2877 cache_info->nexus_info[id]);
2878 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002879}
2880
2881/*
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883% %
2884% %
2885% %
2886+ G e t V i r t u a l P i x e l s F r o m N e x u s %
2887% %
2888% %
2889% %
2890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891%
2892% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2893% pixel cache as defined by the geometry parameters. A pointer to the pixels
2894% is returned if the pixels are transferred, otherwise a NULL is returned.
2895%
2896% The format of the GetVirtualPixelsFromNexus() method is:
2897%
cristy4c08aed2011-07-01 19:47:50 +00002898% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002899% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002900% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2901% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002902%
2903% A description of each parameter follows:
2904%
2905% o image: the image.
2906%
2907% o virtual_pixel_method: the virtual pixel method.
2908%
2909% o x,y,columns,rows: These values define the perimeter of a region of
2910% pixels.
2911%
2912% o nexus_info: the cache nexus to acquire.
2913%
2914% o exception: return any errors or warnings in this structure.
2915%
2916*/
2917
cristybb503372010-05-27 20:51:26 +00002918static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002919 DitherMatrix[64] =
2920 {
2921 0, 48, 12, 60, 3, 51, 15, 63,
2922 32, 16, 44, 28, 35, 19, 47, 31,
2923 8, 56, 4, 52, 11, 59, 7, 55,
2924 40, 24, 36, 20, 43, 27, 39, 23,
2925 2, 50, 14, 62, 1, 49, 13, 61,
2926 34, 18, 46, 30, 33, 17, 45, 29,
2927 10, 58, 6, 54, 9, 57, 5, 53,
2928 42, 26, 38, 22, 41, 25, 37, 21
2929 };
2930
cristybb503372010-05-27 20:51:26 +00002931static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002932{
cristybb503372010-05-27 20:51:26 +00002933 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002934 index;
2935
2936 index=x+DitherMatrix[x & 0x07]-32L;
2937 if (index < 0L)
2938 return(0L);
cristybb503372010-05-27 20:51:26 +00002939 if (index >= (ssize_t) columns)
2940 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002941 return(index);
2942}
2943
cristybb503372010-05-27 20:51:26 +00002944static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002945{
cristybb503372010-05-27 20:51:26 +00002946 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002947 index;
2948
2949 index=y+DitherMatrix[y & 0x07]-32L;
2950 if (index < 0L)
2951 return(0L);
cristybb503372010-05-27 20:51:26 +00002952 if (index >= (ssize_t) rows)
2953 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002954 return(index);
2955}
2956
cristybb503372010-05-27 20:51:26 +00002957static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002958{
2959 if (x < 0L)
2960 return(0L);
cristybb503372010-05-27 20:51:26 +00002961 if (x >= (ssize_t) columns)
2962 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002963 return(x);
2964}
2965
cristybb503372010-05-27 20:51:26 +00002966static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002967{
2968 if (y < 0L)
2969 return(0L);
cristybb503372010-05-27 20:51:26 +00002970 if (y >= (ssize_t) rows)
2971 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002972 return(y);
2973}
2974
cristybb503372010-05-27 20:51:26 +00002975static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002976{
cristybb503372010-05-27 20:51:26 +00002977 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002978}
2979
cristybb503372010-05-27 20:51:26 +00002980static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002981{
cristybb503372010-05-27 20:51:26 +00002982 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002983}
2984
cristybb503372010-05-27 20:51:26 +00002985static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2986 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002987{
2988 MagickModulo
2989 modulo;
2990
cristy6162bb42011-07-18 11:34:09 +00002991 /*
2992 Compute the remainder of dividing offset by extent. It returns not only
2993 the quotient (tile the offset falls in) but also the positive remainer
2994 within that tile such that 0 <= remainder < extent. This method is
2995 essentially a ldiv() using a floored modulo division rather than the
2996 normal default truncated modulo division.
2997 */
cristybb503372010-05-27 20:51:26 +00002998 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002999 if (offset < 0L)
3000 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003001 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003002 return(modulo);
3003}
3004
cristya6577ff2011-09-02 19:54:26 +00003005MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003006 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3007 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003008 ExceptionInfo *exception)
3009{
3010 CacheInfo
3011 *cache_info;
3012
3013 MagickOffsetType
3014 offset;
3015
3016 MagickSizeType
3017 length,
3018 number_pixels;
3019
3020 NexusInfo
3021 **virtual_nexus;
3022
cristy4c08aed2011-07-01 19:47:50 +00003023 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003024 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003025 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003026
3027 RectangleInfo
3028 region;
3029
cristy4c08aed2011-07-01 19:47:50 +00003030 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003031 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003032
cristy4c08aed2011-07-01 19:47:50 +00003033 register const void
3034 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003035
cristy4c08aed2011-07-01 19:47:50 +00003036 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003037 *restrict q;
3038
cristybb503372010-05-27 20:51:26 +00003039 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003040 i,
3041 u;
cristy3ed852e2009-09-05 21:47:34 +00003042
cristy4c08aed2011-07-01 19:47:50 +00003043 register unsigned char
3044 *restrict s;
3045
cristy105ba3c2011-07-18 02:28:38 +00003046 ssize_t
3047 v;
3048
cristy4c08aed2011-07-01 19:47:50 +00003049 void
cristy105ba3c2011-07-18 02:28:38 +00003050 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003051
cristy3ed852e2009-09-05 21:47:34 +00003052 /*
3053 Acquire pixels.
3054 */
cristye7cc7cf2010-09-21 13:26:47 +00003055 assert(image != (const Image *) NULL);
3056 assert(image->signature == MagickSignature);
3057 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003058 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003059 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003060 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003061 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003062 region.x=x;
3063 region.y=y;
3064 region.width=columns;
3065 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003066 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003067 if (pixels == (Quantum *) NULL)
3068 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003069 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003070 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3071 nexus_info->region.x;
3072 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3073 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003074 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3075 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003076 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3077 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003078 {
3079 MagickBooleanType
3080 status;
3081
3082 /*
3083 Pixel request is inside cache extents.
3084 */
cristy4c08aed2011-07-01 19:47:50 +00003085 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003086 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003087 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3088 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003089 return((const Quantum *) NULL);
3090 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003091 {
cristy4c08aed2011-07-01 19:47:50 +00003092 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003093 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003094 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003095 }
cristyacd2ed22011-08-30 01:44:23 +00003096 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003097 }
3098 /*
3099 Pixel request is outside cache extents.
3100 */
cristy4c08aed2011-07-01 19:47:50 +00003101 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003102 virtual_nexus=AcquirePixelCacheNexus(1);
3103 if (virtual_nexus == (NexusInfo **) NULL)
3104 {
cristy4c08aed2011-07-01 19:47:50 +00003105 if (virtual_nexus != (NexusInfo **) NULL)
3106 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003107 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003108 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003109 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003110 }
cristy105ba3c2011-07-18 02:28:38 +00003111 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3112 sizeof(*virtual_pixel));
3113 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003114 switch (virtual_pixel_method)
3115 {
cristy4c08aed2011-07-01 19:47:50 +00003116 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003117 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003118 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003119 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 case MaskVirtualPixelMethod:
3121 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003122 case EdgeVirtualPixelMethod:
3123 case CheckerTileVirtualPixelMethod:
3124 case HorizontalTileVirtualPixelMethod:
3125 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003126 {
cristy4c08aed2011-07-01 19:47:50 +00003127 if (cache_info->metacontent_extent != 0)
3128 {
cristy6162bb42011-07-18 11:34:09 +00003129 /*
3130 Acquire a metacontent buffer.
3131 */
cristya64b85d2011-09-14 01:02:31 +00003132 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003133 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003134 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003135 {
cristy4c08aed2011-07-01 19:47:50 +00003136 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3137 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003138 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003139 return((const Quantum *) NULL);
3140 }
cristy105ba3c2011-07-18 02:28:38 +00003141 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003142 cache_info->metacontent_extent);
3143 }
3144 switch (virtual_pixel_method)
3145 {
3146 case BlackVirtualPixelMethod:
3147 {
cristy30301712011-07-18 15:06:51 +00003148 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3149 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003150 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3151 break;
3152 }
3153 case GrayVirtualPixelMethod:
3154 {
cristy30301712011-07-18 15:06:51 +00003155 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003156 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3157 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003158 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3159 break;
3160 }
3161 case TransparentVirtualPixelMethod:
3162 {
cristy30301712011-07-18 15:06:51 +00003163 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3164 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003165 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3166 break;
3167 }
3168 case MaskVirtualPixelMethod:
3169 case WhiteVirtualPixelMethod:
3170 {
cristy30301712011-07-18 15:06:51 +00003171 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3172 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003173 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3174 break;
3175 }
3176 default:
3177 {
cristy9e0719b2011-12-29 03:45:45 +00003178 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3179 virtual_pixel);
3180 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3181 virtual_pixel);
3182 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3183 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003184 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3185 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003186 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3187 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003188 break;
3189 }
3190 }
cristy3ed852e2009-09-05 21:47:34 +00003191 break;
3192 }
3193 default:
cristy3ed852e2009-09-05 21:47:34 +00003194 break;
cristy3ed852e2009-09-05 21:47:34 +00003195 }
cristybb503372010-05-27 20:51:26 +00003196 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003197 {
cristybb503372010-05-27 20:51:26 +00003198 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003199 {
3200 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003201 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003202 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3203 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003204 {
3205 MagickModulo
3206 x_modulo,
3207 y_modulo;
3208
3209 /*
3210 Transfer a single pixel.
3211 */
3212 length=(MagickSizeType) 1;
3213 switch (virtual_pixel_method)
3214 {
cristy3ed852e2009-09-05 21:47:34 +00003215 default:
3216 {
3217 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003218 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003219 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003220 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003221 break;
3222 }
3223 case RandomVirtualPixelMethod:
3224 {
3225 if (cache_info->random_info == (RandomInfo *) NULL)
3226 cache_info->random_info=AcquireRandomInfo();
3227 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003228 RandomX(cache_info->random_info,cache_info->columns),
3229 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003230 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003231 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003232 break;
3233 }
3234 case DitherVirtualPixelMethod:
3235 {
3236 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003237 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003238 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003239 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003240 break;
3241 }
3242 case TileVirtualPixelMethod:
3243 {
3244 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3245 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3246 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003247 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003248 exception);
cristy4c08aed2011-07-01 19:47:50 +00003249 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003250 break;
3251 }
3252 case MirrorVirtualPixelMethod:
3253 {
3254 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3255 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003256 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003257 x_modulo.remainder-1L;
3258 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3259 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003260 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003261 y_modulo.remainder-1L;
3262 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003263 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003264 exception);
cristy4c08aed2011-07-01 19:47:50 +00003265 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003266 break;
3267 }
3268 case HorizontalTileEdgeVirtualPixelMethod:
3269 {
3270 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3271 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003272 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003273 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003274 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003275 break;
3276 }
3277 case VerticalTileEdgeVirtualPixelMethod:
3278 {
3279 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3280 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003281 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003282 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003283 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3284 break;
3285 }
3286 case BackgroundVirtualPixelMethod:
3287 case BlackVirtualPixelMethod:
3288 case GrayVirtualPixelMethod:
3289 case TransparentVirtualPixelMethod:
3290 case MaskVirtualPixelMethod:
3291 case WhiteVirtualPixelMethod:
3292 {
3293 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003294 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003295 break;
3296 }
3297 case EdgeVirtualPixelMethod:
3298 case CheckerTileVirtualPixelMethod:
3299 {
3300 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3301 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3302 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3303 {
3304 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003305 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003306 break;
3307 }
3308 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3309 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3310 exception);
3311 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3312 break;
3313 }
3314 case HorizontalTileVirtualPixelMethod:
3315 {
3316 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3317 {
3318 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003319 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003320 break;
3321 }
3322 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3323 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3324 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3325 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3326 exception);
3327 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3328 break;
3329 }
3330 case VerticalTileVirtualPixelMethod:
3331 {
3332 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3333 {
3334 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003335 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003336 break;
3337 }
3338 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3339 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3340 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3341 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3342 exception);
3343 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003344 break;
3345 }
3346 }
cristy4c08aed2011-07-01 19:47:50 +00003347 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003348 break;
cristyed231572011-07-14 02:18:59 +00003349 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003350 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003351 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003352 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003353 {
3354 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3355 s+=cache_info->metacontent_extent;
3356 }
cristy3ed852e2009-09-05 21:47:34 +00003357 continue;
3358 }
3359 /*
3360 Transfer a run of pixels.
3361 */
cristy4c08aed2011-07-01 19:47:50 +00003362 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3363 length,1UL,*virtual_nexus,exception);
3364 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003365 break;
cristy4c08aed2011-07-01 19:47:50 +00003366 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003367 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3368 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003369 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003370 {
cristy4c08aed2011-07-01 19:47:50 +00003371 (void) memcpy(s,r,(size_t) length);
3372 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003373 }
3374 }
3375 }
cristy4c08aed2011-07-01 19:47:50 +00003376 /*
3377 Free resources.
3378 */
cristy105ba3c2011-07-18 02:28:38 +00003379 if (virtual_metacontent != (void *) NULL)
3380 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003381 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3382 return(pixels);
3383}
3384
3385/*
3386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3387% %
3388% %
3389% %
3390+ G e t V i r t u a l P i x e l C a c h e %
3391% %
3392% %
3393% %
3394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3395%
3396% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3397% cache as defined by the geometry parameters. A pointer to the pixels
3398% is returned if the pixels are transferred, otherwise a NULL is returned.
3399%
3400% The format of the GetVirtualPixelCache() method is:
3401%
cristy4c08aed2011-07-01 19:47:50 +00003402% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003403% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3404% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003405% ExceptionInfo *exception)
3406%
3407% A description of each parameter follows:
3408%
3409% o image: the image.
3410%
3411% o virtual_pixel_method: the virtual pixel method.
3412%
3413% o x,y,columns,rows: These values define the perimeter of a region of
3414% pixels.
3415%
3416% o exception: return any errors or warnings in this structure.
3417%
3418*/
cristy4c08aed2011-07-01 19:47:50 +00003419static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003420 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3421 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003422{
3423 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003424 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003425
cristy5c9e6f22010-09-17 17:31:01 +00003426 const int
3427 id = GetOpenMPThreadId();
3428
cristy4c08aed2011-07-01 19:47:50 +00003429 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003430 *p;
cristy4c08aed2011-07-01 19:47:50 +00003431
cristye7cc7cf2010-09-21 13:26:47 +00003432 assert(image != (const Image *) NULL);
3433 assert(image->signature == MagickSignature);
3434 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003435 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003436 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003437 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003439 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003440 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003441}
3442
3443/*
3444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3445% %
3446% %
3447% %
3448% G e t V i r t u a l P i x e l Q u e u e %
3449% %
3450% %
3451% %
3452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3453%
cristy4c08aed2011-07-01 19:47:50 +00003454% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3455% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003456%
3457% The format of the GetVirtualPixelQueue() method is:
3458%
cristy4c08aed2011-07-01 19:47:50 +00003459% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003460%
3461% A description of each parameter follows:
3462%
3463% o image: the image.
3464%
3465*/
cristy4c08aed2011-07-01 19:47:50 +00003466MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003467{
3468 CacheInfo
3469 *cache_info;
3470
cristy2036f5c2010-09-19 21:18:17 +00003471 const int
3472 id = GetOpenMPThreadId();
3473
cristy3ed852e2009-09-05 21:47:34 +00003474 assert(image != (const Image *) NULL);
3475 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003476 assert(image->cache != (Cache) NULL);
3477 cache_info=(CacheInfo *) image->cache;
3478 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003479 if (cache_info->methods.get_virtual_pixels_handler !=
3480 (GetVirtualPixelsHandler) NULL)
3481 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003482 assert(id < (int) cache_info->number_threads);
3483 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003484}
3485
3486/*
3487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3488% %
3489% %
3490% %
3491% G e t V i r t u a l P i x e l s %
3492% %
3493% %
3494% %
3495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3496%
3497% GetVirtualPixels() returns an immutable pixel region. If the
3498% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003499% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003500% copy of the pixels or it may point to the original pixels in memory.
3501% Performance is maximized if the selected region is part of one row, or one
3502% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003503% (without a copy) if the image is in memory, or in a memory-mapped file. The
3504% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003505%
3506% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003507% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3508% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3509% access the meta-content (of type void) corresponding to the the
3510% region.
cristy3ed852e2009-09-05 21:47:34 +00003511%
3512% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3513%
3514% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3515% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3516% GetCacheViewAuthenticPixels() instead.
3517%
3518% The format of the GetVirtualPixels() method is:
3519%
cristy4c08aed2011-07-01 19:47:50 +00003520% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003521% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003522% ExceptionInfo *exception)
3523%
3524% A description of each parameter follows:
3525%
3526% o image: the image.
3527%
3528% o x,y,columns,rows: These values define the perimeter of a region of
3529% pixels.
3530%
3531% o exception: return any errors or warnings in this structure.
3532%
3533*/
cristy4c08aed2011-07-01 19:47:50 +00003534MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003535 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3536 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003537{
3538 CacheInfo
3539 *cache_info;
3540
cristy2036f5c2010-09-19 21:18:17 +00003541 const int
3542 id = GetOpenMPThreadId();
3543
cristy4c08aed2011-07-01 19:47:50 +00003544 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003545 *p;
cristy4c08aed2011-07-01 19:47:50 +00003546
cristy3ed852e2009-09-05 21:47:34 +00003547 assert(image != (const Image *) NULL);
3548 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003549 assert(image->cache != (Cache) NULL);
3550 cache_info=(CacheInfo *) image->cache;
3551 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003552 if (cache_info->methods.get_virtual_pixel_handler !=
3553 (GetVirtualPixelHandler) NULL)
3554 return(cache_info->methods.get_virtual_pixel_handler(image,
3555 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003556 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003557 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003558 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003559 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003560}
3561
3562/*
3563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3564% %
3565% %
3566% %
3567+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3568% %
3569% %
3570% %
3571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3572%
cristy4c08aed2011-07-01 19:47:50 +00003573% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3574% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003575%
3576% The format of the GetVirtualPixelsCache() method is:
3577%
cristy4c08aed2011-07-01 19:47:50 +00003578% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003579%
3580% A description of each parameter follows:
3581%
3582% o image: the image.
3583%
3584*/
cristy4c08aed2011-07-01 19:47:50 +00003585static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003586{
3587 CacheInfo
3588 *cache_info;
3589
cristy5c9e6f22010-09-17 17:31:01 +00003590 const int
3591 id = GetOpenMPThreadId();
3592
cristye7cc7cf2010-09-21 13:26:47 +00003593 assert(image != (const Image *) NULL);
3594 assert(image->signature == MagickSignature);
3595 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003596 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003597 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003598 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003599 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003600}
3601
3602/*
3603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604% %
3605% %
3606% %
3607+ G e t V i r t u a l P i x e l s N e x u s %
3608% %
3609% %
3610% %
3611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3612%
3613% GetVirtualPixelsNexus() returns the pixels associated with the specified
3614% cache nexus.
3615%
3616% The format of the GetVirtualPixelsNexus() method is:
3617%
cristy4c08aed2011-07-01 19:47:50 +00003618% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003619% NexusInfo *nexus_info)
3620%
3621% A description of each parameter follows:
3622%
3623% o cache: the pixel cache.
3624%
3625% o nexus_info: the cache nexus to return the colormap pixels.
3626%
3627*/
cristya6577ff2011-09-02 19:54:26 +00003628MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003629 NexusInfo *nexus_info)
3630{
3631 CacheInfo
3632 *cache_info;
3633
cristye7cc7cf2010-09-21 13:26:47 +00003634 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003635 cache_info=(CacheInfo *) cache;
3636 assert(cache_info->signature == MagickSignature);
3637 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003638 return((Quantum *) NULL);
3639 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003640}
3641
3642/*
3643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3644% %
3645% %
3646% %
cristy3ed852e2009-09-05 21:47:34 +00003647+ O p e n P i x e l C a c h e %
3648% %
3649% %
3650% %
3651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3652%
3653% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3654% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003655% metacontent, and memory mapping the cache if it is disk based. The cache
3656% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003657%
3658% The format of the OpenPixelCache() method is:
3659%
3660% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3661% ExceptionInfo *exception)
3662%
3663% A description of each parameter follows:
3664%
3665% o image: the image.
3666%
3667% o mode: ReadMode, WriteMode, or IOMode.
3668%
3669% o exception: return any errors or warnings in this structure.
3670%
3671*/
3672
cristyd43a46b2010-01-21 02:13:41 +00003673static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003674{
3675 cache_info->mapped=MagickFalse;
cristye42639a2012-08-23 01:53:24 +00003676 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3677 (size_t) cache_info->length));
cristy4c08aed2011-07-01 19:47:50 +00003678 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003679 {
3680 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003681 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003682 cache_info->length);
3683 }
3684}
3685
3686static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3687{
3688 CacheInfo
3689 *cache_info;
3690
3691 MagickOffsetType
cristy3ed852e2009-09-05 21:47:34 +00003692 extent,
3693 offset;
3694
3695 cache_info=(CacheInfo *) image->cache;
3696 if (image->debug != MagickFalse)
3697 {
3698 char
3699 format[MaxTextExtent],
3700 message[MaxTextExtent];
3701
cristyb9080c92009-12-01 20:13:26 +00003702 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003703 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003704 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003705 cache_info->cache_filename,cache_info->file,format);
3706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3707 }
3708 if (length != (MagickSizeType) ((MagickOffsetType) length))
3709 return(MagickFalse);
cristy911f2b12012-10-18 14:55:28 +00003710 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3711 if (offset < 0)
cristy3ed852e2009-09-05 21:47:34 +00003712 return(MagickFalse);
cristy911f2b12012-10-18 14:55:28 +00003713 if ((MagickSizeType) offset >= length)
cristy3ed852e2009-09-05 21:47:34 +00003714 return(MagickTrue);
cristy911f2b12012-10-18 14:55:28 +00003715 extent=(MagickOffsetType) length-1;
cristy3b5a2cf2012-10-18 14:50:08 +00003716#if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3717 {
3718 MagickOffsetType
3719 count;
3720
cristy911f2b12012-10-18 14:55:28 +00003721 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
cristy3b5a2cf2012-10-18 14:50:08 +00003722 if (count != (MagickOffsetType) 1)
3723 return(MagickFalse);
3724 }
3725#else
3726 {
3727 int
3728 status;
3729
cristy911f2b12012-10-18 14:55:28 +00003730 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
cristy3b5a2cf2012-10-18 14:50:08 +00003731 if (status != 0)
3732 return(MagickFalse);
3733 }
3734#endif
3735 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003736}
3737
3738static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3739 ExceptionInfo *exception)
3740{
cristy3ed852e2009-09-05 21:47:34 +00003741 CacheInfo
3742 *cache_info,
3743 source_info;
3744
cristyf3a6a9d2010-11-07 21:02:56 +00003745 char
3746 format[MaxTextExtent],
3747 message[MaxTextExtent];
3748
cristy4c08aed2011-07-01 19:47:50 +00003749 MagickBooleanType
3750 status;
3751
cristy3ed852e2009-09-05 21:47:34 +00003752 MagickSizeType
3753 length,
3754 number_pixels;
3755
cristy3ed852e2009-09-05 21:47:34 +00003756 size_t
cristye076a6e2010-08-15 19:59:43 +00003757 columns,
cristy3ed852e2009-09-05 21:47:34 +00003758 packet_size;
3759
cristye7cc7cf2010-09-21 13:26:47 +00003760 assert(image != (const Image *) NULL);
3761 assert(image->signature == MagickSignature);
3762 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003763 if (image->debug != MagickFalse)
3764 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3765 if ((image->columns == 0) || (image->rows == 0))
3766 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3767 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003768 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003769 source_info=(*cache_info);
3770 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003771 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003772 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003773 cache_info->storage_class=image->storage_class;
3774 cache_info->colorspace=image->colorspace;
cristy8a46d822012-08-28 23:32:39 +00003775 cache_info->alpha_trait=image->alpha_trait;
cristy183a5c72012-01-30 01:40:35 +00003776 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003777 cache_info->rows=image->rows;
3778 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003779 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003780 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003781 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3782 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003783 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003784 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003785 if (image->ping != MagickFalse)
3786 {
cristy73724512010-04-12 14:43:14 +00003787 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003788 cache_info->pixels=(Quantum *) NULL;
3789 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003790 cache_info->length=0;
3791 return(MagickTrue);
3792 }
cristy3ed852e2009-09-05 21:47:34 +00003793 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003794 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003795 if (image->metacontent_extent != 0)
3796 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003797 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003798 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003799 if (cache_info->columns != columns)
3800 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3801 image->filename);
3802 cache_info->length=length;
3803 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003804 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003805 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003806 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3807 {
3808 status=AcquireMagickResource(MemoryResource,cache_info->length);
3809 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3810 (cache_info->type == MemoryCache))
3811 {
cristyd43a46b2010-01-21 02:13:41 +00003812 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003813 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003814 cache_info->pixels=source_info.pixels;
3815 else
3816 {
3817 /*
3818 Create memory pixel cache.
3819 */
cristy4c08aed2011-07-01 19:47:50 +00003820 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003821 if (image->debug != MagickFalse)
3822 {
cristy32cacff2011-12-31 03:36:27 +00003823 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003824 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003825 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3826 cache_info->filename,cache_info->mapped != MagickFalse ?
3827 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003828 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003829 format);
cristy3ed852e2009-09-05 21:47:34 +00003830 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3831 message);
3832 }
cristy3ed852e2009-09-05 21:47:34 +00003833 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003834 cache_info->metacontent=(void *) NULL;
3835 if (cache_info->metacontent_extent != 0)
3836 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003837 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003838 if ((source_info.storage_class != UndefinedClass) &&
3839 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003840 {
cristy4c08aed2011-07-01 19:47:50 +00003841 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003842 exception);
3843 RelinquishPixelCachePixels(&source_info);
3844 }
cristy4c08aed2011-07-01 19:47:50 +00003845 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003846 }
3847 }
3848 RelinquishMagickResource(MemoryResource,cache_info->length);
3849 }
3850 /*
3851 Create pixel cache on disk.
3852 */
3853 status=AcquireMagickResource(DiskResource,cache_info->length);
3854 if (status == MagickFalse)
3855 {
3856 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003857 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003858 return(MagickFalse);
3859 }
cristy413f1302012-01-01 17:48:27 +00003860 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3861 {
3862 (void) ClosePixelCacheOnDisk(cache_info);
3863 *cache_info->cache_filename='\0';
3864 }
cristy3ed852e2009-09-05 21:47:34 +00003865 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3866 {
3867 RelinquishMagickResource(DiskResource,cache_info->length);
3868 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3869 image->filename);
3870 return(MagickFalse);
3871 }
3872 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3873 cache_info->length);
3874 if (status == MagickFalse)
3875 {
3876 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3877 image->filename);
3878 return(MagickFalse);
3879 }
cristyed231572011-07-14 02:18:59 +00003880 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003881 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003882 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003883 cache_info->type=DiskCache;
3884 else
3885 {
3886 status=AcquireMagickResource(MapResource,cache_info->length);
3887 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3888 (cache_info->type != MemoryCache))
3889 cache_info->type=DiskCache;
3890 else
3891 {
cristy4c08aed2011-07-01 19:47:50 +00003892 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003893 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003894 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003895 {
cristy3ed852e2009-09-05 21:47:34 +00003896 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003897 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003898 }
3899 else
3900 {
3901 /*
3902 Create file-backed memory-mapped pixel cache.
3903 */
cristy4c08aed2011-07-01 19:47:50 +00003904 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003905 (void) ClosePixelCacheOnDisk(cache_info);
3906 cache_info->type=MapCache;
3907 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003908 cache_info->metacontent=(void *) NULL;
3909 if (cache_info->metacontent_extent != 0)
3910 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003911 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003912 if ((source_info.storage_class != UndefinedClass) &&
3913 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003914 {
3915 status=ClonePixelCachePixels(cache_info,&source_info,
3916 exception);
3917 RelinquishPixelCachePixels(&source_info);
3918 }
3919 if (image->debug != MagickFalse)
3920 {
cristy413f1302012-01-01 17:48:27 +00003921 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003922 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003923 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003924 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003925 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003926 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003927 format);
cristy3ed852e2009-09-05 21:47:34 +00003928 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3929 message);
3930 }
cristy4c08aed2011-07-01 19:47:50 +00003931 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003932 }
3933 }
3934 RelinquishMagickResource(MapResource,cache_info->length);
3935 }
cristy4c08aed2011-07-01 19:47:50 +00003936 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003937 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003938 {
3939 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3940 RelinquishPixelCachePixels(&source_info);
3941 }
3942 if (image->debug != MagickFalse)
3943 {
cristyb9080c92009-12-01 20:13:26 +00003944 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003945 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003946 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003947 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003948 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003949 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003950 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3951 }
cristy4c08aed2011-07-01 19:47:50 +00003952 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003953}
3954
3955/*
3956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3957% %
3958% %
3959% %
3960+ P e r s i s t P i x e l C a c h e %
3961% %
3962% %
3963% %
3964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3965%
3966% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3967% persistent pixel cache is one that resides on disk and is not destroyed
3968% when the program exits.
3969%
3970% The format of the PersistPixelCache() method is:
3971%
3972% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3973% const MagickBooleanType attach,MagickOffsetType *offset,
3974% ExceptionInfo *exception)
3975%
3976% A description of each parameter follows:
3977%
3978% o image: the image.
3979%
3980% o filename: the persistent pixel cache filename.
3981%
cristyf3a6a9d2010-11-07 21:02:56 +00003982% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003983%
cristy3ed852e2009-09-05 21:47:34 +00003984% o initialize: A value other than zero initializes the persistent pixel
3985% cache.
3986%
3987% o offset: the offset in the persistent cache to store pixels.
3988%
3989% o exception: return any errors or warnings in this structure.
3990%
3991*/
3992MagickExport MagickBooleanType PersistPixelCache(Image *image,
3993 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3994 ExceptionInfo *exception)
3995{
3996 CacheInfo
3997 *cache_info,
3998 *clone_info;
3999
4000 Image
4001 clone_image;
4002
cristy3ed852e2009-09-05 21:47:34 +00004003 MagickBooleanType
4004 status;
4005
cristye076a6e2010-08-15 19:59:43 +00004006 ssize_t
4007 page_size;
4008
cristy3ed852e2009-09-05 21:47:34 +00004009 assert(image != (Image *) NULL);
4010 assert(image->signature == MagickSignature);
4011 if (image->debug != MagickFalse)
4012 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4013 assert(image->cache != (void *) NULL);
4014 assert(filename != (const char *) NULL);
4015 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004016 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004017 cache_info=(CacheInfo *) image->cache;
4018 assert(cache_info->signature == MagickSignature);
4019 if (attach != MagickFalse)
4020 {
4021 /*
cristy01b7eb02009-09-10 23:10:14 +00004022 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004023 */
4024 if (image->debug != MagickFalse)
4025 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004026 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004027 (void) CopyMagickString(cache_info->cache_filename,filename,
4028 MaxTextExtent);
4029 cache_info->type=DiskCache;
4030 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004031 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004032 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004033 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004034 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004035 }
cristy01b7eb02009-09-10 23:10:14 +00004036 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4037 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004038 {
cristyf84a1932010-01-03 18:00:18 +00004039 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004040 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004041 (cache_info->reference_count == 1))
4042 {
4043 int
4044 status;
4045
4046 /*
cristy01b7eb02009-09-10 23:10:14 +00004047 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004048 */
cristy320684d2011-09-23 14:55:47 +00004049 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004050 if (status == 0)
4051 {
4052 (void) CopyMagickString(cache_info->cache_filename,filename,
4053 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004054 *offset+=cache_info->length+page_size-(cache_info->length %
4055 page_size);
cristyf84a1932010-01-03 18:00:18 +00004056 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004057 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004058 if (image->debug != MagickFalse)
4059 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4060 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004061 return(MagickTrue);
4062 }
4063 }
cristyf84a1932010-01-03 18:00:18 +00004064 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004065 }
4066 /*
cristy01b7eb02009-09-10 23:10:14 +00004067 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004068 */
4069 clone_image=(*image);
4070 clone_info=(CacheInfo *) clone_image.cache;
4071 image->cache=ClonePixelCache(cache_info);
4072 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4073 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4074 cache_info->type=DiskCache;
4075 cache_info->offset=(*offset);
4076 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004077 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004078 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004079 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004080 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004081 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4082 return(status);
4083}
4084
4085/*
4086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4087% %
4088% %
4089% %
cristyc11dace2012-01-24 16:39:46 +00004090+ Q u e u e A u t h e n t i c P i x e l C a c h e N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00004091% %
4092% %
4093% %
4094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4095%
cristyc11dace2012-01-24 16:39:46 +00004096% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4097% defined by the region rectangle and returns a pointer to the region. This
4098% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004099% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4100% pixels are transferred, otherwise a NULL is returned.
4101%
cristyc11dace2012-01-24 16:39:46 +00004102% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004103%
cristyc11dace2012-01-24 16:39:46 +00004104% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004105% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004106% const MagickBooleanType clone,NexusInfo *nexus_info,
4107% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004108%
4109% A description of each parameter follows:
4110%
4111% o image: the image.
4112%
4113% o x,y,columns,rows: These values define the perimeter of a region of
4114% pixels.
4115%
4116% o nexus_info: the cache nexus to set.
4117%
cristy65dbf172011-10-06 17:32:04 +00004118% o clone: clone the pixel cache.
4119%
cristy3ed852e2009-09-05 21:47:34 +00004120% o exception: return any errors or warnings in this structure.
4121%
4122*/
cristyc11dace2012-01-24 16:39:46 +00004123MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4124 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004125 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004126{
4127 CacheInfo
4128 *cache_info;
4129
4130 MagickOffsetType
4131 offset;
4132
4133 MagickSizeType
4134 number_pixels;
4135
4136 RectangleInfo
4137 region;
4138
4139 /*
4140 Validate pixel cache geometry.
4141 */
cristye7cc7cf2010-09-21 13:26:47 +00004142 assert(image != (const Image *) NULL);
4143 assert(image->signature == MagickSignature);
4144 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004145 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004146 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004147 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004148 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004149 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4150 {
4151 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004152 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004153 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004154 }
cristybb503372010-05-27 20:51:26 +00004155 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4156 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004157 {
4158 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004159 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004160 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004161 }
4162 offset=(MagickOffsetType) y*cache_info->columns+x;
4163 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004164 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004165 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4166 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4167 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004168 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004169 /*
4170 Return pixel cache.
4171 */
4172 region.x=x;
4173 region.y=y;
4174 region.width=columns;
4175 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004176 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004177}
4178
4179/*
4180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4181% %
4182% %
4183% %
4184+ Q u e u e A u t h e n t i c P i x e l s C a c h e %
4185% %
4186% %
4187% %
4188%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4189%
4190% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4191% defined by the region rectangle and returns a pointer to the region. This
4192% region is subsequently transferred from the pixel cache with
4193% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4194% pixels are transferred, otherwise a NULL is returned.
4195%
4196% The format of the QueueAuthenticPixelsCache() method is:
4197%
cristy4c08aed2011-07-01 19:47:50 +00004198% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004199% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004200% ExceptionInfo *exception)
4201%
4202% A description of each parameter follows:
4203%
4204% o image: the image.
4205%
4206% o x,y,columns,rows: These values define the perimeter of a region of
4207% pixels.
4208%
4209% o exception: return any errors or warnings in this structure.
4210%
4211*/
cristy4c08aed2011-07-01 19:47:50 +00004212static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004213 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004214 ExceptionInfo *exception)
4215{
4216 CacheInfo
4217 *cache_info;
4218
cristy5c9e6f22010-09-17 17:31:01 +00004219 const int
4220 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004221
cristy4c08aed2011-07-01 19:47:50 +00004222 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004223 *q;
cristy4c08aed2011-07-01 19:47:50 +00004224
cristye7cc7cf2010-09-21 13:26:47 +00004225 assert(image != (const Image *) NULL);
4226 assert(image->signature == MagickSignature);
4227 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004228 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004229 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004230 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004231 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004232 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004233 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004234}
4235
4236/*
4237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4238% %
4239% %
4240% %
4241% Q u e u e A u t h e n t i c P i x e l s %
4242% %
4243% %
4244% %
4245%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4246%
4247% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004248% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004249% region is returned, otherwise NULL is returned. The returned pointer may
4250% point to a temporary working buffer for the pixels or it may point to the
4251% final location of the pixels in memory.
4252%
4253% Write-only access means that any existing pixel values corresponding to
4254% the region are ignored. This is useful if the initial image is being
4255% created from scratch, or if the existing pixel values are to be
4256% completely replaced without need to refer to their pre-existing values.
4257% The application is free to read and write the pixel buffer returned by
4258% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4259% initialize the pixel array values. Initializing pixel array values is the
4260% application's responsibility.
4261%
4262% Performance is maximized if the selected region is part of one row, or
4263% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004264% pixels in-place (without a copy) if the image is in memory, or in a
4265% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004266% by the user.
4267%
4268% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004269% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4270% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4271% obtain the meta-content (of type void) corresponding to the region.
4272% Once the Quantum (and/or Quantum) array has been updated, the
4273% changes must be saved back to the underlying image using
4274% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004275%
4276% The format of the QueueAuthenticPixels() method is:
4277%
cristy4c08aed2011-07-01 19:47:50 +00004278% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004279% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004280% ExceptionInfo *exception)
4281%
4282% A description of each parameter follows:
4283%
4284% o image: the image.
4285%
4286% o x,y,columns,rows: These values define the perimeter of a region of
4287% pixels.
4288%
4289% o exception: return any errors or warnings in this structure.
4290%
4291*/
cristy4c08aed2011-07-01 19:47:50 +00004292MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004293 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004294 ExceptionInfo *exception)
4295{
4296 CacheInfo
4297 *cache_info;
4298
cristy2036f5c2010-09-19 21:18:17 +00004299 const int
4300 id = GetOpenMPThreadId();
4301
cristy4c08aed2011-07-01 19:47:50 +00004302 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004303 *q;
cristy4c08aed2011-07-01 19:47:50 +00004304
cristy3ed852e2009-09-05 21:47:34 +00004305 assert(image != (Image *) NULL);
4306 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004307 assert(image->cache != (Cache) NULL);
4308 cache_info=(CacheInfo *) image->cache;
4309 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004310 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004311 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004312 {
cristyc36c8822012-02-14 14:02:36 +00004313 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4314 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004315 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004316 }
cristy2036f5c2010-09-19 21:18:17 +00004317 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004318 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004319 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004320 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004321}
4322
4323/*
4324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4325% %
4326% %
4327% %
cristy4c08aed2011-07-01 19:47:50 +00004328+ R e a d P i x e l C a c h e M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00004329% %
4330% %
4331% %
4332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4333%
cristy4c08aed2011-07-01 19:47:50 +00004334% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004335% the pixel cache.
4336%
cristy4c08aed2011-07-01 19:47:50 +00004337% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004338%
cristy4c08aed2011-07-01 19:47:50 +00004339% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004340% NexusInfo *nexus_info,ExceptionInfo *exception)
4341%
4342% A description of each parameter follows:
4343%
4344% o cache_info: the pixel cache.
4345%
cristy4c08aed2011-07-01 19:47:50 +00004346% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004347%
4348% o exception: return any errors or warnings in this structure.
4349%
4350*/
cristy4c08aed2011-07-01 19:47:50 +00004351static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004352 NexusInfo *nexus_info,ExceptionInfo *exception)
4353{
4354 MagickOffsetType
4355 count,
4356 offset;
4357
4358 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004359 extent,
4360 length;
cristy3ed852e2009-09-05 21:47:34 +00004361
cristybb503372010-05-27 20:51:26 +00004362 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004363 y;
4364
cristy4c08aed2011-07-01 19:47:50 +00004365 register unsigned char
4366 *restrict q;
4367
cristybb503372010-05-27 20:51:26 +00004368 size_t
cristy3ed852e2009-09-05 21:47:34 +00004369 rows;
4370
cristy4c08aed2011-07-01 19:47:50 +00004371 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004372 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004373 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004374 return(MagickTrue);
4375 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4376 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004377 length=(MagickSizeType) nexus_info->region.width*
4378 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004379 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004380 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004381 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004382 switch (cache_info->type)
4383 {
4384 case MemoryCache:
4385 case MapCache:
4386 {
cristy4c08aed2011-07-01 19:47:50 +00004387 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004388 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004389
4390 /*
cristy4c08aed2011-07-01 19:47:50 +00004391 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004392 */
cristydd341db2010-03-04 19:06:38 +00004393 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004394 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004395 {
cristy48078b12010-09-23 17:11:01 +00004396 length=extent;
cristydd341db2010-03-04 19:06:38 +00004397 rows=1UL;
4398 }
cristy4c08aed2011-07-01 19:47:50 +00004399 p=(unsigned char *) cache_info->metacontent+offset*
4400 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004401 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004402 {
cristy8f036fe2010-09-18 02:02:00 +00004403 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004404 p+=cache_info->metacontent_extent*cache_info->columns;
4405 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004406 }
4407 break;
4408 }
4409 case DiskCache:
4410 {
4411 /*
cristy4c08aed2011-07-01 19:47:50 +00004412 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004413 */
4414 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4415 {
4416 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4417 cache_info->cache_filename);
4418 return(MagickFalse);
4419 }
cristydd341db2010-03-04 19:06:38 +00004420 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004421 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004422 {
cristy48078b12010-09-23 17:11:01 +00004423 length=extent;
cristydd341db2010-03-04 19:06:38 +00004424 rows=1UL;
4425 }
cristy48078b12010-09-23 17:11:01 +00004426 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004427 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004428 {
cristy48078b12010-09-23 17:11:01 +00004429 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004430 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004431 cache_info->metacontent_extent,length,(unsigned char *) q);
4432 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004433 break;
4434 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004435 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004436 }
cristyc11dace2012-01-24 16:39:46 +00004437 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4438 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004439 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004440 {
4441 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4442 cache_info->cache_filename);
4443 return(MagickFalse);
4444 }
4445 break;
4446 }
4447 default:
4448 break;
4449 }
4450 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004451 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004452 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004453 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004454 nexus_info->region.width,(double) nexus_info->region.height,(double)
4455 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004456 return(MagickTrue);
4457}
4458
4459/*
4460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4461% %
4462% %
4463% %
4464+ R e a d P i x e l C a c h e P i x e l s %
4465% %
4466% %
4467% %
4468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4469%
4470% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4471% cache.
4472%
4473% The format of the ReadPixelCachePixels() method is:
4474%
4475% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4476% NexusInfo *nexus_info,ExceptionInfo *exception)
4477%
4478% A description of each parameter follows:
4479%
4480% o cache_info: the pixel cache.
4481%
4482% o nexus_info: the cache nexus to read the pixels.
4483%
4484% o exception: return any errors or warnings in this structure.
4485%
4486*/
4487static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4488 NexusInfo *nexus_info,ExceptionInfo *exception)
4489{
4490 MagickOffsetType
4491 count,
4492 offset;
4493
4494 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004495 extent,
4496 length;
cristy3ed852e2009-09-05 21:47:34 +00004497
cristy4c08aed2011-07-01 19:47:50 +00004498 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004499 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004500
cristye076a6e2010-08-15 19:59:43 +00004501 register ssize_t
4502 y;
4503
cristybb503372010-05-27 20:51:26 +00004504 size_t
cristy3ed852e2009-09-05 21:47:34 +00004505 rows;
4506
cristy4c08aed2011-07-01 19:47:50 +00004507 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004508 return(MagickTrue);
4509 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4510 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004511 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004512 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004513 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004514 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004515 q=nexus_info->pixels;
4516 switch (cache_info->type)
4517 {
4518 case MemoryCache:
4519 case MapCache:
4520 {
cristy4c08aed2011-07-01 19:47:50 +00004521 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004522 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004523
4524 /*
4525 Read pixels from memory.
4526 */
cristydd341db2010-03-04 19:06:38 +00004527 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004528 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004529 {
cristy48078b12010-09-23 17:11:01 +00004530 length=extent;
cristydd341db2010-03-04 19:06:38 +00004531 rows=1UL;
4532 }
cristyed231572011-07-14 02:18:59 +00004533 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004534 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004535 {
cristy8f036fe2010-09-18 02:02:00 +00004536 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004537 p+=cache_info->number_channels*cache_info->columns;
4538 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004539 }
4540 break;
4541 }
4542 case DiskCache:
4543 {
4544 /*
4545 Read pixels from disk.
4546 */
4547 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4548 {
4549 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4550 cache_info->cache_filename);
4551 return(MagickFalse);
4552 }
cristydd341db2010-03-04 19:06:38 +00004553 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004554 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004555 {
cristy48078b12010-09-23 17:11:01 +00004556 length=extent;
cristydd341db2010-03-04 19:06:38 +00004557 rows=1UL;
4558 }
cristybb503372010-05-27 20:51:26 +00004559 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004560 {
4561 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004562 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004563 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004564 break;
4565 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004566 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004567 }
cristyc11dace2012-01-24 16:39:46 +00004568 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4569 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004570 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004571 {
4572 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4573 cache_info->cache_filename);
4574 return(MagickFalse);
4575 }
4576 break;
4577 }
4578 default:
4579 break;
4580 }
4581 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004582 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004583 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004584 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004585 nexus_info->region.width,(double) nexus_info->region.height,(double)
4586 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004587 return(MagickTrue);
4588}
4589
4590/*
4591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4592% %
4593% %
4594% %
4595+ R e f e r e n c e P i x e l C a c h e %
4596% %
4597% %
4598% %
4599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4600%
4601% ReferencePixelCache() increments the reference count associated with the
4602% pixel cache returning a pointer to the cache.
4603%
4604% The format of the ReferencePixelCache method is:
4605%
4606% Cache ReferencePixelCache(Cache cache_info)
4607%
4608% A description of each parameter follows:
4609%
4610% o cache_info: the pixel cache.
4611%
4612*/
cristya6577ff2011-09-02 19:54:26 +00004613MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004614{
4615 CacheInfo
4616 *cache_info;
4617
4618 assert(cache != (Cache *) NULL);
4619 cache_info=(CacheInfo *) cache;
4620 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004621 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004622 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004623 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004624 return(cache_info);
4625}
4626
4627/*
4628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4629% %
4630% %
4631% %
4632+ S e t P i x e l C a c h e M e t h o d s %
4633% %
4634% %
4635% %
4636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4637%
4638% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4639%
4640% The format of the SetPixelCacheMethods() method is:
4641%
4642% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4643%
4644% A description of each parameter follows:
4645%
4646% o cache: the pixel cache.
4647%
4648% o cache_methods: Specifies a pointer to a CacheMethods structure.
4649%
4650*/
cristya6577ff2011-09-02 19:54:26 +00004651MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004652{
4653 CacheInfo
4654 *cache_info;
4655
4656 GetOneAuthenticPixelFromHandler
4657 get_one_authentic_pixel_from_handler;
4658
4659 GetOneVirtualPixelFromHandler
4660 get_one_virtual_pixel_from_handler;
4661
4662 /*
4663 Set cache pixel methods.
4664 */
4665 assert(cache != (Cache) NULL);
4666 assert(cache_methods != (CacheMethods *) NULL);
4667 cache_info=(CacheInfo *) cache;
4668 assert(cache_info->signature == MagickSignature);
4669 if (cache_info->debug != MagickFalse)
4670 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4671 cache_info->filename);
4672 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4673 cache_info->methods.get_virtual_pixel_handler=
4674 cache_methods->get_virtual_pixel_handler;
4675 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4676 cache_info->methods.destroy_pixel_handler=
4677 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004678 if (cache_methods->get_virtual_metacontent_from_handler !=
4679 (GetVirtualMetacontentFromHandler) NULL)
4680 cache_info->methods.get_virtual_metacontent_from_handler=
4681 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004682 if (cache_methods->get_authentic_pixels_handler !=
4683 (GetAuthenticPixelsHandler) NULL)
4684 cache_info->methods.get_authentic_pixels_handler=
4685 cache_methods->get_authentic_pixels_handler;
4686 if (cache_methods->queue_authentic_pixels_handler !=
4687 (QueueAuthenticPixelsHandler) NULL)
4688 cache_info->methods.queue_authentic_pixels_handler=
4689 cache_methods->queue_authentic_pixels_handler;
4690 if (cache_methods->sync_authentic_pixels_handler !=
4691 (SyncAuthenticPixelsHandler) NULL)
4692 cache_info->methods.sync_authentic_pixels_handler=
4693 cache_methods->sync_authentic_pixels_handler;
4694 if (cache_methods->get_authentic_pixels_from_handler !=
4695 (GetAuthenticPixelsFromHandler) NULL)
4696 cache_info->methods.get_authentic_pixels_from_handler=
4697 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004698 if (cache_methods->get_authentic_metacontent_from_handler !=
4699 (GetAuthenticMetacontentFromHandler) NULL)
4700 cache_info->methods.get_authentic_metacontent_from_handler=
4701 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004702 get_one_virtual_pixel_from_handler=
4703 cache_info->methods.get_one_virtual_pixel_from_handler;
4704 if (get_one_virtual_pixel_from_handler !=
4705 (GetOneVirtualPixelFromHandler) NULL)
4706 cache_info->methods.get_one_virtual_pixel_from_handler=
4707 cache_methods->get_one_virtual_pixel_from_handler;
4708 get_one_authentic_pixel_from_handler=
4709 cache_methods->get_one_authentic_pixel_from_handler;
4710 if (get_one_authentic_pixel_from_handler !=
4711 (GetOneAuthenticPixelFromHandler) NULL)
4712 cache_info->methods.get_one_authentic_pixel_from_handler=
4713 cache_methods->get_one_authentic_pixel_from_handler;
4714}
4715
4716/*
4717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4718% %
4719% %
4720% %
4721+ S e t P i x e l C a c h e N e x u s P i x e l s %
4722% %
4723% %
4724% %
4725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4726%
4727% SetPixelCacheNexusPixels() defines the region of the cache for the
4728% specified cache nexus.
4729%
4730% The format of the SetPixelCacheNexusPixels() method is:
4731%
cristy265a2b22012-05-11 12:48:50 +00004732% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004733% const RectangleInfo *region,NexusInfo *nexus_info,
4734% ExceptionInfo *exception)
4735%
4736% A description of each parameter follows:
4737%
4738% o image: the image.
4739%
cristy265a2b22012-05-11 12:48:50 +00004740% o mode: ReadMode, WriteMode, or IOMode.
4741%
cristy3ed852e2009-09-05 21:47:34 +00004742% o region: A pointer to the RectangleInfo structure that defines the
4743% region of this particular cache nexus.
4744%
4745% o nexus_info: the cache nexus to set.
4746%
4747% o exception: return any errors or warnings in this structure.
4748%
4749*/
cristyabd6e372010-09-15 19:11:26 +00004750
cristyf1832792012-05-08 18:38:18 +00004751static inline MagickBooleanType AcquireCacheNexusPixels(
4752 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4753 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004754{
4755 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4756 return(MagickFalse);
4757 nexus_info->mapped=MagickFalse;
cristye42639a2012-08-23 01:53:24 +00004758 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4759 (size_t) nexus_info->length));
cristy4c08aed2011-07-01 19:47:50 +00004760 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004761 {
4762 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004763 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004764 nexus_info->length);
4765 }
cristy4c08aed2011-07-01 19:47:50 +00004766 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004767 {
4768 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004769 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004770 cache_info->filename);
4771 return(MagickFalse);
4772 }
4773 return(MagickTrue);
4774}
4775
cristyadf82722012-05-11 17:34:16 +00004776static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4777 const MapMode mode)
4778{
cristyfc5845e2012-05-11 18:18:13 +00004779 if (mode == ReadMode)
4780 {
4781 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4782 return;
4783 }
4784 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004785}
4786
cristy265a2b22012-05-11 12:48:50 +00004787static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004788 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4789{
4790 CacheInfo
4791 *cache_info;
4792
4793 MagickBooleanType
4794 status;
4795
cristy3ed852e2009-09-05 21:47:34 +00004796 MagickSizeType
4797 length,
4798 number_pixels;
4799
cristy3ed852e2009-09-05 21:47:34 +00004800 cache_info=(CacheInfo *) image->cache;
4801 assert(cache_info->signature == MagickSignature);
4802 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004803 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004804 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004805 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004806 {
cristybb503372010-05-27 20:51:26 +00004807 ssize_t
cristybad067a2010-02-15 17:20:55 +00004808 x,
4809 y;
cristy3ed852e2009-09-05 21:47:34 +00004810
cristyeaedf062010-05-29 22:36:02 +00004811 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4812 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004813 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4814 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004815 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004816 ((nexus_info->region.width == cache_info->columns) ||
4817 ((nexus_info->region.width % cache_info->columns) == 0)))))
4818 {
4819 MagickOffsetType
4820 offset;
4821
4822 /*
4823 Pixels are accessed directly from memory.
4824 */
4825 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4826 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004827 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004828 offset;
4829 nexus_info->metacontent=(void *) NULL;
4830 if (cache_info->metacontent_extent != 0)
4831 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4832 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004833 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004834 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004835 }
4836 }
4837 /*
4838 Pixels are stored in a cache region until they are synced to the cache.
4839 */
4840 number_pixels=(MagickSizeType) nexus_info->region.width*
4841 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004842 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004843 if (cache_info->metacontent_extent != 0)
4844 length+=number_pixels*cache_info->metacontent_extent;
4845 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004846 {
4847 nexus_info->length=length;
4848 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4849 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004850 {
4851 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004852 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004853 }
cristy3ed852e2009-09-05 21:47:34 +00004854 }
4855 else
4856 if (nexus_info->length != length)
4857 {
4858 RelinquishCacheNexusPixels(nexus_info);
4859 nexus_info->length=length;
4860 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4861 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004862 {
4863 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004864 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004865 }
cristy3ed852e2009-09-05 21:47:34 +00004866 }
4867 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004868 nexus_info->metacontent=(void *) NULL;
4869 if (cache_info->metacontent_extent != 0)
4870 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004871 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004872 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004873 return(nexus_info->pixels);
4874}
4875
4876/*
4877%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4878% %
4879% %
4880% %
4881% S e t P i x e l C a c h e V i r t u a l M e t h o d %
4882% %
4883% %
4884% %
4885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4886%
4887% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4888% pixel cache and returns the previous setting. A virtual pixel is any pixel
4889% access that is outside the boundaries of the image cache.
4890%
4891% The format of the SetPixelCacheVirtualMethod() method is:
4892%
cristy387430f2012-02-07 13:09:46 +00004893% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4894% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004895%
4896% A description of each parameter follows:
4897%
4898% o image: the image.
4899%
4900% o virtual_pixel_method: choose the type of virtual pixel.
4901%
cristy387430f2012-02-07 13:09:46 +00004902% o exception: return any errors or warnings in this structure.
4903%
cristy3ed852e2009-09-05 21:47:34 +00004904*/
cristy3d4cb882012-02-07 19:11:26 +00004905
4906static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4907 ExceptionInfo *exception)
4908{
4909 CacheInfo
4910 *cache_info;
4911
cristyf2719112012-05-06 18:38:46 +00004912 CacheView
4913 *image_view;
4914
cristy3d4cb882012-02-07 19:11:26 +00004915 MagickBooleanType
4916 status;
4917
4918 ssize_t
4919 y;
4920
4921 assert(image != (Image *) NULL);
4922 assert(image->signature == MagickSignature);
4923 if (image->debug != MagickFalse)
4924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4925 assert(image->cache != (Cache) NULL);
4926 cache_info=(CacheInfo *) image->cache;
4927 assert(cache_info->signature == MagickSignature);
cristy8a46d822012-08-28 23:32:39 +00004928 image->alpha_trait=BlendPixelTrait;
cristy3d4cb882012-02-07 19:11:26 +00004929 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004930 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004931#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +00004932 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00004933 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004934#endif
4935 for (y=0; y < (ssize_t) image->rows; y++)
4936 {
cristy3d4cb882012-02-07 19:11:26 +00004937 register Quantum
4938 *restrict q;
4939
4940 register ssize_t
4941 x;
4942
4943 if (status == MagickFalse)
4944 continue;
cristy23d198a2012-03-13 13:48:08 +00004945 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004946 if (q == (Quantum *) NULL)
4947 {
4948 status=MagickFalse;
4949 continue;
4950 }
4951 for (x=0; x < (ssize_t) image->columns; x++)
4952 {
4953 SetPixelAlpha(image,alpha,q);
4954 q+=GetPixelChannels(image);
4955 }
cristy23d198a2012-03-13 13:48:08 +00004956 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004957 }
cristy23d198a2012-03-13 13:48:08 +00004958 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004959 return(status);
4960}
4961
cristy387430f2012-02-07 13:09:46 +00004962MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4963 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004964{
4965 CacheInfo
4966 *cache_info;
4967
4968 VirtualPixelMethod
4969 method;
4970
4971 assert(image != (Image *) NULL);
4972 assert(image->signature == MagickSignature);
4973 if (image->debug != MagickFalse)
4974 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4975 assert(image->cache != (Cache) NULL);
4976 cache_info=(CacheInfo *) image->cache;
4977 assert(cache_info->signature == MagickSignature);
4978 method=cache_info->virtual_pixel_method;
4979 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy13c10082012-05-29 11:22:12 +00004980 if ((image->columns != 0) && (image->rows != 0))
4981 switch (virtual_pixel_method)
cristy387430f2012-02-07 13:09:46 +00004982 {
cristy13c10082012-05-29 11:22:12 +00004983 case BackgroundVirtualPixelMethod:
4984 {
cristy8a46d822012-08-28 23:32:39 +00004985 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4986 (image->alpha_trait != BlendPixelTrait))
cristy13c10082012-05-29 11:22:12 +00004987 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy6386b792012-06-23 17:44:57 +00004988 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4989 (IsGrayColorspace(image->colorspace) != MagickFalse))
cristyb09db112012-07-11 12:04:31 +00004990 (void) TransformImageColorspace(image,RGBColorspace,exception);
cristy13c10082012-05-29 11:22:12 +00004991 break;
4992 }
4993 case TransparentVirtualPixelMethod:
4994 {
cristy8a46d822012-08-28 23:32:39 +00004995 if (image->alpha_trait != BlendPixelTrait)
cristy13c10082012-05-29 11:22:12 +00004996 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4997 break;
4998 }
4999 default:
5000 break;
cristy387430f2012-02-07 13:09:46 +00005001 }
cristy3ed852e2009-09-05 21:47:34 +00005002 return(method);
5003}
5004
5005/*
5006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5007% %
5008% %
5009% %
5010+ S y n c A u t h e n t i c P i x e l C a c h e N e x u s %
5011% %
5012% %
5013% %
5014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5015%
5016% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5017% in-memory or disk cache. The method returns MagickTrue if the pixel region
5018% is synced, otherwise MagickFalse.
5019%
5020% The format of the SyncAuthenticPixelCacheNexus() method is:
5021%
5022% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5023% NexusInfo *nexus_info,ExceptionInfo *exception)
5024%
5025% A description of each parameter follows:
5026%
5027% o image: the image.
5028%
5029% o nexus_info: the cache nexus to sync.
5030%
5031% o exception: return any errors or warnings in this structure.
5032%
5033*/
cristya6577ff2011-09-02 19:54:26 +00005034MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005035 NexusInfo *nexus_info,ExceptionInfo *exception)
5036{
5037 CacheInfo
5038 *cache_info;
5039
5040 MagickBooleanType
5041 status;
5042
5043 /*
5044 Transfer pixels to the cache.
5045 */
5046 assert(image != (Image *) NULL);
5047 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005048 if (image->cache == (Cache) NULL)
5049 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5050 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005051 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005052 if (cache_info->type == UndefinedCache)
5053 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005054 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005055 return(MagickTrue);
5056 assert(cache_info->signature == MagickSignature);
5057 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005058 if ((cache_info->metacontent_extent != 0) &&
5059 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005060 return(MagickFalse);
5061 return(status);
5062}
5063
5064/*
5065%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5066% %
5067% %
5068% %
5069+ S y n c A u t h e n t i c P i x e l C a c h e %
5070% %
5071% %
5072% %
5073%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5074%
5075% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5076% or disk cache. The method returns MagickTrue if the pixel region is synced,
5077% otherwise MagickFalse.
5078%
5079% The format of the SyncAuthenticPixelsCache() method is:
5080%
5081% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5082% ExceptionInfo *exception)
5083%
5084% A description of each parameter follows:
5085%
5086% o image: the image.
5087%
5088% o exception: return any errors or warnings in this structure.
5089%
5090*/
5091static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5092 ExceptionInfo *exception)
5093{
5094 CacheInfo
5095 *cache_info;
5096
cristy5c9e6f22010-09-17 17:31:01 +00005097 const int
5098 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005099
cristy4c08aed2011-07-01 19:47:50 +00005100 MagickBooleanType
5101 status;
5102
cristye7cc7cf2010-09-21 13:26:47 +00005103 assert(image != (Image *) NULL);
5104 assert(image->signature == MagickSignature);
5105 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005106 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005107 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005108 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005109 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5110 exception);
5111 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005112}
5113
5114/*
5115%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5116% %
5117% %
5118% %
5119% S y n c A u t h e n t i c P i x e l s %
5120% %
5121% %
5122% %
5123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5124%
5125% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5126% The method returns MagickTrue if the pixel region is flushed, otherwise
5127% MagickFalse.
5128%
5129% The format of the SyncAuthenticPixels() method is:
5130%
5131% MagickBooleanType SyncAuthenticPixels(Image *image,
5132% ExceptionInfo *exception)
5133%
5134% A description of each parameter follows:
5135%
5136% o image: the image.
5137%
5138% o exception: return any errors or warnings in this structure.
5139%
5140*/
5141MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5142 ExceptionInfo *exception)
5143{
5144 CacheInfo
5145 *cache_info;
5146
cristy2036f5c2010-09-19 21:18:17 +00005147 const int
5148 id = GetOpenMPThreadId();
5149
cristy4c08aed2011-07-01 19:47:50 +00005150 MagickBooleanType
5151 status;
5152
cristy3ed852e2009-09-05 21:47:34 +00005153 assert(image != (Image *) NULL);
5154 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005155 assert(image->cache != (Cache) NULL);
5156 cache_info=(CacheInfo *) image->cache;
5157 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005158 if (cache_info->methods.sync_authentic_pixels_handler !=
5159 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005160 {
5161 status=cache_info->methods.sync_authentic_pixels_handler(image,
5162 exception);
5163 return(status);
5164 }
cristy2036f5c2010-09-19 21:18:17 +00005165 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005166 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5167 exception);
5168 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005169}
5170
5171/*
5172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5173% %
5174% %
5175% %
cristyd1dd6e42011-09-04 01:46:08 +00005176+ S y n c I m a g e P i x e l C a c h e %
cristy6e437132011-08-12 13:02:19 +00005177% %
5178% %
5179% %
5180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5181%
5182% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5183% The method returns MagickTrue if the pixel region is flushed, otherwise
5184% MagickFalse.
5185%
5186% The format of the SyncImagePixelCache() method is:
5187%
5188% MagickBooleanType SyncImagePixelCache(Image *image,
5189% ExceptionInfo *exception)
5190%
5191% A description of each parameter follows:
5192%
5193% o image: the image.
5194%
5195% o exception: return any errors or warnings in this structure.
5196%
5197*/
cristyd1dd6e42011-09-04 01:46:08 +00005198MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005199 ExceptionInfo *exception)
5200{
5201 CacheInfo
5202 *cache_info;
5203
5204 assert(image != (Image *) NULL);
5205 assert(exception != (ExceptionInfo *) NULL);
5206 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5207 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5208}
5209
5210/*
5211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5212% %
5213% %
5214% %
cristy4c08aed2011-07-01 19:47:50 +00005215+ W r i t e P i x e l C a c h e M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00005216% %
5217% %
5218% %
5219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5220%
cristy4c08aed2011-07-01 19:47:50 +00005221% WritePixelCacheMetacontent() writes the meta-content to the specified region
5222% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005223%
cristy4c08aed2011-07-01 19:47:50 +00005224% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005225%
cristy4c08aed2011-07-01 19:47:50 +00005226% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005227% NexusInfo *nexus_info,ExceptionInfo *exception)
5228%
5229% A description of each parameter follows:
5230%
5231% o cache_info: the pixel cache.
5232%
cristy4c08aed2011-07-01 19:47:50 +00005233% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005234%
5235% o exception: return any errors or warnings in this structure.
5236%
5237*/
cristy4c08aed2011-07-01 19:47:50 +00005238static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005239 NexusInfo *nexus_info,ExceptionInfo *exception)
5240{
5241 MagickOffsetType
5242 count,
5243 offset;
5244
5245 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005246 extent,
5247 length;
cristy3ed852e2009-09-05 21:47:34 +00005248
cristy4c08aed2011-07-01 19:47:50 +00005249 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005250 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005251
cristybb503372010-05-27 20:51:26 +00005252 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005253 y;
5254
cristybb503372010-05-27 20:51:26 +00005255 size_t
cristy3ed852e2009-09-05 21:47:34 +00005256 rows;
5257
cristy4c08aed2011-07-01 19:47:50 +00005258 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005259 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005260 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005261 return(MagickTrue);
5262 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5263 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005264 length=(MagickSizeType) nexus_info->region.width*
5265 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005266 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005267 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005268 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005269 switch (cache_info->type)
5270 {
5271 case MemoryCache:
5272 case MapCache:
5273 {
cristy4c08aed2011-07-01 19:47:50 +00005274 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005275 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005276
5277 /*
cristy4c08aed2011-07-01 19:47:50 +00005278 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005279 */
cristydd341db2010-03-04 19:06:38 +00005280 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005281 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005282 {
cristy48078b12010-09-23 17:11:01 +00005283 length=extent;
cristydd341db2010-03-04 19:06:38 +00005284 rows=1UL;
5285 }
cristy4c08aed2011-07-01 19:47:50 +00005286 q=(unsigned char *) cache_info->metacontent+offset*
5287 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005288 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005289 {
cristy8f036fe2010-09-18 02:02:00 +00005290 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005291 p+=nexus_info->region.width*cache_info->metacontent_extent;
5292 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005293 }
5294 break;
5295 }
5296 case DiskCache:
5297 {
5298 /*
cristy4c08aed2011-07-01 19:47:50 +00005299 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005300 */
5301 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5302 {
5303 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5304 cache_info->cache_filename);
5305 return(MagickFalse);
5306 }
cristydd341db2010-03-04 19:06:38 +00005307 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005308 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005309 {
cristy48078b12010-09-23 17:11:01 +00005310 length=extent;
cristydd341db2010-03-04 19:06:38 +00005311 rows=1UL;
5312 }
cristy48078b12010-09-23 17:11:01 +00005313 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005314 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005315 {
cristy48078b12010-09-23 17:11:01 +00005316 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005317 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005318 cache_info->metacontent_extent,length,(const unsigned char *) p);
5319 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005320 break;
cristy4c08aed2011-07-01 19:47:50 +00005321 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005322 offset+=cache_info->columns;
5323 }
cristyc11dace2012-01-24 16:39:46 +00005324 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5325 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005326 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005327 {
5328 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5329 cache_info->cache_filename);
5330 return(MagickFalse);
5331 }
5332 break;
5333 }
5334 default:
5335 break;
5336 }
5337 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005338 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005339 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005340 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005341 nexus_info->region.width,(double) nexus_info->region.height,(double)
5342 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005343 return(MagickTrue);
5344}
5345
5346/*
5347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5348% %
5349% %
5350% %
5351+ W r i t e C a c h e P i x e l s %
5352% %
5353% %
5354% %
5355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5356%
5357% WritePixelCachePixels() writes image pixels to the specified region of the
5358% pixel cache.
5359%
5360% The format of the WritePixelCachePixels() method is:
5361%
5362% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5363% NexusInfo *nexus_info,ExceptionInfo *exception)
5364%
5365% A description of each parameter follows:
5366%
5367% o cache_info: the pixel cache.
5368%
5369% o nexus_info: the cache nexus to write the pixels.
5370%
5371% o exception: return any errors or warnings in this structure.
5372%
5373*/
5374static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5375 NexusInfo *nexus_info,ExceptionInfo *exception)
5376{
5377 MagickOffsetType
5378 count,
5379 offset;
5380
5381 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005382 extent,
5383 length;
cristy3ed852e2009-09-05 21:47:34 +00005384
cristy4c08aed2011-07-01 19:47:50 +00005385 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005386 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005387
cristybb503372010-05-27 20:51:26 +00005388 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005389 y;
5390
cristybb503372010-05-27 20:51:26 +00005391 size_t
cristy3ed852e2009-09-05 21:47:34 +00005392 rows;
5393
cristy4c08aed2011-07-01 19:47:50 +00005394 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005395 return(MagickTrue);
5396 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5397 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005398 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005399 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005400 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005401 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005402 p=nexus_info->pixels;
5403 switch (cache_info->type)
5404 {
5405 case MemoryCache:
5406 case MapCache:
5407 {
cristy4c08aed2011-07-01 19:47:50 +00005408 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005409 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005410
5411 /*
5412 Write pixels to memory.
5413 */
cristydd341db2010-03-04 19:06:38 +00005414 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005415 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005416 {
cristy48078b12010-09-23 17:11:01 +00005417 length=extent;
cristydd341db2010-03-04 19:06:38 +00005418 rows=1UL;
5419 }
cristyed231572011-07-14 02:18:59 +00005420 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005421 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005422 {
cristy8f036fe2010-09-18 02:02:00 +00005423 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005424 p+=nexus_info->region.width*cache_info->number_channels;
5425 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005426 }
5427 break;
5428 }
5429 case DiskCache:
5430 {
5431 /*
5432 Write pixels to disk.
5433 */
5434 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5435 {
5436 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5437 cache_info->cache_filename);
5438 return(MagickFalse);
5439 }
cristydd341db2010-03-04 19:06:38 +00005440 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005441 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005442 {
cristy48078b12010-09-23 17:11:01 +00005443 length=extent;
cristydd341db2010-03-04 19:06:38 +00005444 rows=1UL;
5445 }
cristybb503372010-05-27 20:51:26 +00005446 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005447 {
5448 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005449 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005450 p);
5451 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005452 break;
cristyed231572011-07-14 02:18:59 +00005453 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005454 offset+=cache_info->columns;
5455 }
cristyc11dace2012-01-24 16:39:46 +00005456 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5457 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005458 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005459 {
5460 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5461 cache_info->cache_filename);
5462 return(MagickFalse);
5463 }
5464 break;
5465 }
5466 default:
5467 break;
5468 }
5469 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005470 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005471 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005472 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005473 nexus_info->region.width,(double) nexus_info->region.height,(double)
5474 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005475 return(MagickTrue);
5476}