blob: 5e238d970f7e3ffe7c2621d5b1c148fd388623c9 [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"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000069#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000070#if defined(MAGICKCORE_ZLIB_DELEGATE)
71#include "zlib.h"
72#endif
73
74/*
cristy30097232010-07-01 02:16:30 +000075 Define declarations.
76*/
77#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
cristyc11dace2012-01-24 16:39:46 +000078#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
79 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
cristy30097232010-07-01 02:16:30 +000080
81/*
cristy3ed852e2009-09-05 21:47:34 +000082 Typedef declarations.
83*/
84typedef struct _MagickModulo
85{
cristybb503372010-05-27 20:51:26 +000086 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000087 quotient,
88 remainder;
89} MagickModulo;
90
91struct _NexusInfo
92{
93 MagickBooleanType
94 mapped;
95
96 RectangleInfo
97 region;
98
99 MagickSizeType
100 length;
101
cristy4c08aed2011-07-01 19:47:50 +0000102 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000103 *cache,
104 *pixels;
105
cristy4c08aed2011-07-01 19:47:50 +0000106 void
107 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000108
cristybb503372010-05-27 20:51:26 +0000109 size_t
cristy3ed852e2009-09-05 21:47:34 +0000110 signature;
111};
112
113/*
114 Forward declarations.
115*/
116#if defined(__cplusplus) || defined(c_plusplus)
117extern "C" {
118#endif
119
cristy4c08aed2011-07-01 19:47:50 +0000120static const Quantum
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
cristy4c08aed2011-07-01 19:47:50 +0000125static const void
126 *GetVirtualMetacontentFromCache(const Image *);
127
cristy3ed852e2009-09-05 21:47:34 +0000128static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000129 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000130 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000131 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000132 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000133 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000134 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000135 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
136 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000137 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000138 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
139
cristy4c08aed2011-07-01 19:47:50 +0000140static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000141 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000143 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
144 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000145 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000146 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000147
148#if defined(__cplusplus) || defined(c_plusplus)
149}
150#endif
151
152/*
153 Global declarations.
154*/
155static volatile MagickBooleanType
156 instantiate_cache = MagickFalse;
157
158static SemaphoreInfo
159 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristya6577ff2011-09-02 19:54:26 +0000183MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
cristya64b85d2011-09-14 01:02:31 +0000188 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000203 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000204 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000208 return((Cache ) cache_info);
209}
210
211/*
212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213% %
214% %
215% %
216% A c q u i r e P i x e l C a c h e N e x u s %
217% %
218% %
219% %
220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221%
222% AcquirePixelCacheNexus() allocates the NexusInfo structure.
223%
224% The format of the AcquirePixelCacheNexus method is:
225%
cristybb503372010-05-27 20:51:26 +0000226% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000227%
228% A description of each parameter follows:
229%
230% o number_threads: the number of nexus threads.
231%
232*/
cristya6577ff2011-09-02 19:54:26 +0000233MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000234{
cristy3ed852e2009-09-05 21:47:34 +0000235 NexusInfo
236 **nexus_info;
237
cristye076a6e2010-08-15 19:59:43 +0000238 register ssize_t
239 i;
240
cristya64b85d2011-09-14 01:02:31 +0000241 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000242 sizeof(*nexus_info));
243 if (nexus_info == (NexusInfo **) NULL)
244 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000245 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
246 sizeof(**nexus_info));
247 if (nexus_info[0] == (NexusInfo *) NULL)
248 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
249 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000250 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000251 {
cristye5f87c82012-02-14 12:44:17 +0000252 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000253 nexus_info[i]->signature=MagickSignature;
254 }
255 return(nexus_info);
256}
257
258/*
259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260% %
261% %
262% %
cristyd43a46b2010-01-21 02:13:41 +0000263+ A c q u i r e P i x e l C a c h e P i x e l s %
264% %
265% %
266% %
267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268%
269% AcquirePixelCachePixels() returns the pixels associated with the specified
270% image.
271%
272% The format of the AcquirePixelCachePixels() method is:
273%
274% const void *AcquirePixelCachePixels(const Image *image,
275% MagickSizeType *length,ExceptionInfo *exception)
276%
277% A description of each parameter follows:
278%
279% o image: the image.
280%
281% o length: the pixel cache length.
282%
283% o exception: return any errors or warnings in this structure.
284%
285*/
cristyd1dd6e42011-09-04 01:46:08 +0000286MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000287 MagickSizeType *length,ExceptionInfo *exception)
288{
289 CacheInfo
290 *cache_info;
291
292 assert(image != (const Image *) NULL);
293 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000294 assert(exception != (ExceptionInfo *) NULL);
295 assert(exception->signature == MagickSignature);
296 assert(image->cache != (Cache) NULL);
297 cache_info=(CacheInfo *) image->cache;
298 assert(cache_info->signature == MagickSignature);
299 *length=0;
300 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
301 return((const void *) NULL);
302 *length=cache_info->length;
303 return((const void *) cache_info->pixels);
304}
305
306/*
307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
308% %
309% %
310% %
cristyf34a1452009-10-24 22:29:27 +0000311+ C a c h e C o m p o n e n t G e n e s i s %
312% %
313% %
314% %
315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
316%
317% CacheComponentGenesis() instantiates the cache component.
318%
319% The format of the CacheComponentGenesis method is:
320%
321% MagickBooleanType CacheComponentGenesis(void)
322%
323*/
cristy5ff4eaf2011-09-03 01:38:02 +0000324MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000325{
cristy165b6092009-10-26 13:52:10 +0000326 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000327 return(MagickTrue);
328}
329
330/*
331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332% %
333% %
334% %
335+ C a c h e C o m p o n e n t T e r m i n u s %
336% %
337% %
338% %
339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340%
341% CacheComponentTerminus() destroys the cache component.
342%
343% The format of the CacheComponentTerminus() method is:
344%
345% CacheComponentTerminus(void)
346%
347*/
cristy5ff4eaf2011-09-03 01:38:02 +0000348MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000349{
cristy18b17442009-10-25 18:36:48 +0000350 if (cache_semaphore == (SemaphoreInfo *) NULL)
351 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000352 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000353 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000354 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000355 DestroySemaphoreInfo(&cache_semaphore);
356}
357
358/*
359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
360% %
361% %
362% %
cristy3ed852e2009-09-05 21:47:34 +0000363+ C l o n e P i x e l C a c h e %
364% %
365% %
366% %
367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
368%
369% ClonePixelCache() clones a pixel cache.
370%
371% The format of the ClonePixelCache() method is:
372%
373% Cache ClonePixelCache(const Cache cache)
374%
375% A description of each parameter follows:
376%
377% o cache: the pixel cache.
378%
379*/
cristya6577ff2011-09-02 19:54:26 +0000380MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000381{
382 CacheInfo
383 *clone_info;
384
385 const CacheInfo
386 *cache_info;
387
cristy9f027d12011-09-21 01:17:17 +0000388 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000389 cache_info=(const CacheInfo *) cache;
390 assert(cache_info->signature == MagickSignature);
391 if (cache_info->debug != MagickFalse)
392 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
393 cache_info->filename);
394 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
395 if (clone_info == (Cache) NULL)
396 return((Cache) NULL);
397 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
398 return((Cache ) clone_info);
399}
400
401/*
402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403% %
404% %
405% %
cristy60c44a82009-10-07 00:58:49 +0000406+ 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 +0000407% %
408% %
409% %
410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
411% ClonePixelCachePixels() clones the source pixel cache to the destination
412% cache.
413%
414% The format of the ClonePixelCachePixels() method is:
415%
416% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
417% CacheInfo *source_info,ExceptionInfo *exception)
418%
419% A description of each parameter follows:
420%
421% o cache_info: the pixel cache.
422%
423% o source_info: the source pixel cache.
424%
425% o exception: return any errors or warnings in this structure.
426%
427*/
428
429static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
430{
431 int
432 status;
433
cristy5ee247a2010-02-12 15:42:34 +0000434 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000435 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000436 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000437 {
438 status=close(cache_info->file);
439 cache_info->file=(-1);
440 RelinquishMagickResource(FileResource,1);
441 }
cristyf84a1932010-01-03 18:00:18 +0000442 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000443 return(status == -1 ? MagickFalse : MagickTrue);
444}
445
cristy3ed852e2009-09-05 21:47:34 +0000446static inline MagickSizeType MagickMax(const MagickSizeType x,
447 const MagickSizeType y)
448{
449 if (x > y)
450 return(x);
451 return(y);
452}
453
454static inline MagickSizeType MagickMin(const MagickSizeType x,
455 const MagickSizeType y)
456{
457 if (x < y)
458 return(x);
459 return(y);
460}
461
462static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
463 const MapMode mode)
464{
465 int
466 file;
467
468 /*
469 Open pixel cache on disk.
470 */
cristyf84a1932010-01-03 18:00:18 +0000471 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000472 if (cache_info->file != -1)
473 {
cristyf84a1932010-01-03 18:00:18 +0000474 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000475 return(MagickTrue); /* cache already open */
476 }
cristy3ed852e2009-09-05 21:47:34 +0000477 if (*cache_info->cache_filename == '\0')
478 file=AcquireUniqueFileResource(cache_info->cache_filename);
479 else
480 switch (mode)
481 {
482 case ReadMode:
483 {
cristy18c6c272011-09-23 14:40:37 +0000484 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000485 break;
486 }
487 case WriteMode:
488 {
cristy18c6c272011-09-23 14:40:37 +0000489 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
490 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000491 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000492 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000493 break;
494 }
495 case IOMode:
496 default:
497 {
cristy18c6c272011-09-23 14:40:37 +0000498 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000499 O_EXCL,S_MODE);
500 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000501 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000502 break;
503 }
504 }
505 if (file == -1)
506 {
cristyf84a1932010-01-03 18:00:18 +0000507 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000508 return(MagickFalse);
509 }
510 (void) AcquireMagickResource(FileResource,1);
511 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000512 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000513 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000514 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000515 return(MagickTrue);
516}
517
518static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
519 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000520 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000521{
522 register MagickOffsetType
523 i;
524
525 ssize_t
526 count;
527
cristy08a88202010-03-04 19:18:05 +0000528 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000529#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000530 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000531 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000532 {
cristyf84a1932010-01-03 18:00:18 +0000533 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000534 return((MagickOffsetType) -1);
535 }
536#endif
537 count=0;
538 for (i=0; i < (MagickOffsetType) length; i+=count)
539 {
540#if !defined(MAGICKCORE_HAVE_PREAD)
541 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
542 (MagickSizeType) SSIZE_MAX));
543#else
544 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000545 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000546#endif
547 if (count > 0)
548 continue;
549 count=0;
550 if (errno != EINTR)
551 {
552 i=(-1);
553 break;
554 }
555 }
556#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000557 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000558#endif
559 return(i);
560}
561
562static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
563 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000564 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000565{
566 register MagickOffsetType
567 i;
568
569 ssize_t
570 count;
571
cristy08a88202010-03-04 19:18:05 +0000572 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000573#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000574 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000575 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000576 {
cristyf84a1932010-01-03 18:00:18 +0000577 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 return((MagickOffsetType) -1);
579 }
580#endif
581 count=0;
582 for (i=0; i < (MagickOffsetType) length; i+=count)
583 {
584#if !defined(MAGICKCORE_HAVE_PWRITE)
585 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
586 (MagickSizeType) SSIZE_MAX));
587#else
588 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000589 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000590#endif
591 if (count > 0)
592 continue;
593 count=0;
594 if (errno != EINTR)
595 {
596 i=(-1);
597 break;
598 }
599 }
600#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000601 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000602#endif
603 return(i);
604}
605
cristy4c08aed2011-07-01 19:47:50 +0000606static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000607 CacheInfo *cache_info,ExceptionInfo *exception)
608{
609 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000610 count;
cristy3ed852e2009-09-05 21:47:34 +0000611
cristy4c08aed2011-07-01 19:47:50 +0000612 register MagickOffsetType
613 i;
cristye076a6e2010-08-15 19:59:43 +0000614
cristybb503372010-05-27 20:51:26 +0000615 size_t
cristy4c08aed2011-07-01 19:47:50 +0000616 length;
cristy3ed852e2009-09-05 21:47:34 +0000617
cristy4c08aed2011-07-01 19:47:50 +0000618 unsigned char
619 *blob;
620
621 /*
622 Clone pixel cache (both caches on disk).
623 */
cristy3ed852e2009-09-05 21:47:34 +0000624 if (cache_info->debug != MagickFalse)
625 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000626 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000627 sizeof(*blob));
628 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000629 {
cristy4c08aed2011-07-01 19:47:50 +0000630 (void) ThrowMagickException(exception,GetMagickModule(),
631 ResourceLimitError,"MemoryAllocationFailed","`%s'",
632 cache_info->filename);
633 return(MagickFalse);
634 }
cristy3dedf062011-07-02 14:07:40 +0000635 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000636 {
637 blob=(unsigned char *) RelinquishMagickMemory(blob);
638 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
639 cache_info->cache_filename);
640 return(MagickFalse);
641 }
cristy3dedf062011-07-02 14:07:40 +0000642 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000643 {
644 (void) ClosePixelCacheOnDisk(cache_info);
645 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000646 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
647 clone_info->cache_filename);
648 return(MagickFalse);
649 }
cristy4c08aed2011-07-01 19:47:50 +0000650 count=0;
651 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000652 {
cristy4c08aed2011-07-01 19:47:50 +0000653 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
654 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
655 blob);
656 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000657 {
cristy4c08aed2011-07-01 19:47:50 +0000658 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
659 cache_info->cache_filename);
660 break;
cristy3ed852e2009-09-05 21:47:34 +0000661 }
cristy4c08aed2011-07-01 19:47:50 +0000662 length=(size_t) count;
663 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
664 if ((MagickSizeType) count != length)
665 {
666 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
667 clone_info->cache_filename);
668 break;
669 }
670 }
671 (void) ClosePixelCacheOnDisk(clone_info);
672 (void) ClosePixelCacheOnDisk(cache_info);
673 blob=(unsigned char *) RelinquishMagickMemory(blob);
674 if (i < (MagickOffsetType) cache_info->length)
675 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000676 return(MagickTrue);
677}
678
cristyfd24a062012-01-02 14:46:34 +0000679static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000680 CacheInfo *cache_info,ExceptionInfo *exception)
681{
682 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000683 count;
cristy3ed852e2009-09-05 21:47:34 +0000684
cristy4c08aed2011-07-01 19:47:50 +0000685 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000686 {
cristy3ed852e2009-09-05 21:47:34 +0000687 /*
cristy4c08aed2011-07-01 19:47:50 +0000688 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000689 */
cristy4c08aed2011-07-01 19:47:50 +0000690 if (cache_info->debug != MagickFalse)
691 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
692 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
693 cache_info->length);
694 return(MagickTrue);
695 }
696 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
697 {
698 /*
699 Clone pixel cache (one cache on disk, one in memory).
700 */
701 if (cache_info->debug != MagickFalse)
702 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
703 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000704 {
cristy4c08aed2011-07-01 19:47:50 +0000705 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000706 cache_info->cache_filename);
707 return(MagickFalse);
708 }
cristy4c08aed2011-07-01 19:47:50 +0000709 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
710 cache_info->length,(unsigned char *) clone_info->pixels);
711 (void) ClosePixelCacheOnDisk(cache_info);
712 if ((MagickSizeType) count != cache_info->length)
713 {
714 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
715 cache_info->cache_filename);
716 return(MagickFalse);
717 }
718 return(MagickTrue);
719 }
720 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
721 {
722 /*
723 Clone pixel cache (one cache on disk, one in memory).
724 */
725 if (clone_info->debug != MagickFalse)
726 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
727 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
728 {
729 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
730 clone_info->cache_filename);
731 return(MagickFalse);
732 }
733 count=WritePixelCacheRegion(clone_info,clone_info->offset,
734 clone_info->length,(unsigned char *) cache_info->pixels);
735 (void) ClosePixelCacheOnDisk(clone_info);
736 if ((MagickSizeType) count != clone_info->length)
737 {
738 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
739 clone_info->cache_filename);
740 return(MagickFalse);
741 }
742 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000743 }
744 /*
cristy4c08aed2011-07-01 19:47:50 +0000745 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000746 */
cristy4c08aed2011-07-01 19:47:50 +0000747 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000748}
749
cristyfd24a062012-01-02 14:46:34 +0000750static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000751 CacheInfo *cache_info,ExceptionInfo *exception)
752{
cristy4c08aed2011-07-01 19:47:50 +0000753 MagickBooleanType
754 status;
cristy3ed852e2009-09-05 21:47:34 +0000755
cristy4c08aed2011-07-01 19:47:50 +0000756 MagickOffsetType
757 cache_offset,
758 clone_offset,
759 count;
760
761 register ssize_t
762 x;
763
cristyfd24a062012-01-02 14:46:34 +0000764 register unsigned char
765 *p;
766
cristy4c08aed2011-07-01 19:47:50 +0000767 size_t
cristy3ed852e2009-09-05 21:47:34 +0000768 length;
769
cristy4c08aed2011-07-01 19:47:50 +0000770 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000771 y;
772
cristy4c08aed2011-07-01 19:47:50 +0000773 unsigned char
774 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000775
cristy4c08aed2011-07-01 19:47:50 +0000776 /*
777 Clone pixel cache (unoptimized).
778 */
cristy3ed852e2009-09-05 21:47:34 +0000779 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000780 {
cristy4c08aed2011-07-01 19:47:50 +0000781 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
782 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
783 else
784 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
786 else
787 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
789 else
790 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
791 }
cristyed231572011-07-14 02:18:59 +0000792 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
793 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000794 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000795 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000796 if (blob == (unsigned char *) NULL)
797 {
798 (void) ThrowMagickException(exception,GetMagickModule(),
799 ResourceLimitError,"MemoryAllocationFailed","`%s'",
800 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000801 return(MagickFalse);
802 }
cristy4c08aed2011-07-01 19:47:50 +0000803 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
804 cache_offset=0;
805 clone_offset=0;
806 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000807 {
cristy4c08aed2011-07-01 19:47:50 +0000808 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000809 {
cristy4c08aed2011-07-01 19:47:50 +0000810 blob=(unsigned char *) RelinquishMagickMemory(blob);
811 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000812 cache_info->cache_filename);
813 return(MagickFalse);
814 }
cristy4c08aed2011-07-01 19:47:50 +0000815 cache_offset=cache_info->offset;
816 }
817 if (clone_info->type == DiskCache)
818 {
cristy3dedf062011-07-02 14:07:40 +0000819 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000820 {
cristy4c08aed2011-07-01 19:47:50 +0000821 blob=(unsigned char *) RelinquishMagickMemory(blob);
822 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
823 clone_info->cache_filename);
824 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000825 }
cristy4c08aed2011-07-01 19:47:50 +0000826 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000827 }
828 /*
cristy4c08aed2011-07-01 19:47:50 +0000829 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000830 */
cristy4c08aed2011-07-01 19:47:50 +0000831 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000832 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000833 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000834 {
cristy4c08aed2011-07-01 19:47:50 +0000835 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000836 {
cristy9e0719b2011-12-29 03:45:45 +0000837 register ssize_t
838 i;
839
cristy3ed852e2009-09-05 21:47:34 +0000840 /*
cristy4c08aed2011-07-01 19:47:50 +0000841 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000842 */
cristyed231572011-07-14 02:18:59 +0000843 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000844 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000845 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000846 else
847 {
cristyfd24a062012-01-02 14:46:34 +0000848 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000849 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000850 {
cristy4c08aed2011-07-01 19:47:50 +0000851 status=MagickFalse;
852 break;
cristy3ed852e2009-09-05 21:47:34 +0000853 }
854 }
cristy4c08aed2011-07-01 19:47:50 +0000855 cache_offset+=length;
856 if ((y < (ssize_t) clone_info->rows) &&
857 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000858 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000859 {
cristy9e0719b2011-12-29 03:45:45 +0000860 PixelChannel
861 channel;
862
863 PixelTrait
864 traits;
865
866 ssize_t
867 offset;
868
cristy4c08aed2011-07-01 19:47:50 +0000869 /*
cristy3b8fe922011-12-29 18:56:23 +0000870 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000871 */
cristy9e0719b2011-12-29 03:45:45 +0000872 channel=clone_info->channel_map[i].channel;
873 traits=cache_info->channel_map[channel].traits;
874 if (traits == UndefinedPixelTrait)
875 {
cristy0f4425e2011-12-31 20:33:02 +0000876 clone_offset+=sizeof(Quantum);
877 continue;
cristy9e0719b2011-12-29 03:45:45 +0000878 }
cristy0f4425e2011-12-31 20:33:02 +0000879 offset=cache_info->channel_map[channel].offset;
880 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000881 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
882 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000883 else
884 {
cristy0f4425e2011-12-31 20:33:02 +0000885 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000886 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000887 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000888 {
cristy0f4425e2011-12-31 20:33:02 +0000889 status=MagickFalse;
890 break;
cristy4c08aed2011-07-01 19:47:50 +0000891 }
892 }
cristy9e0719b2011-12-29 03:45:45 +0000893 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000894 }
895 }
cristyed231572011-07-14 02:18:59 +0000896 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000897 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
898 for ( ; x < (ssize_t) clone_info->columns; x++)
899 {
900 /*
cristy9e0719b2011-12-29 03:45:45 +0000901 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000902 */
903 if (clone_info->type != DiskCache)
904 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
905 length);
906 else
907 {
908 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
909 if ((MagickSizeType) count != length)
910 {
911 status=MagickFalse;
912 break;
913 }
914 }
915 clone_offset+=length;
916 }
917 }
cristyed231572011-07-14 02:18:59 +0000918 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000919 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
920 for ( ; y < (ssize_t) clone_info->rows; y++)
921 {
922 /*
cristy9e0719b2011-12-29 03:45:45 +0000923 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000924 */
925 for (x=0; x < (ssize_t) clone_info->columns; x++)
926 {
927 if (clone_info->type != DiskCache)
928 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
929 length);
930 else
931 {
932 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
933 if ((MagickSizeType) count != length)
934 {
935 status=MagickFalse;
936 break;
937 }
938 }
939 clone_offset+=length;
940 }
941 }
cristy9e0719b2011-12-29 03:45:45 +0000942 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000943 (clone_info->metacontent_extent != 0))
944 {
945 /*
946 Clone metacontent.
947 */
948 for (y=0; y < (ssize_t) cache_info->rows; y++)
949 {
950 for (x=0; x < (ssize_t) cache_info->columns; x++)
951 {
952 /*
953 Read a set of metacontent.
954 */
955 length=cache_info->metacontent_extent;
956 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000957 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000958 else
959 {
cristyfd24a062012-01-02 14:46:34 +0000960 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000961 if ((MagickSizeType) count != length)
962 {
963 status=MagickFalse;
964 break;
965 }
966 }
967 cache_offset+=length;
968 if ((y < (ssize_t) clone_info->rows) &&
969 (x < (ssize_t) clone_info->columns))
970 {
971 /*
972 Write a set of metacontent.
973 */
974 length=clone_info->metacontent_extent;
975 if (clone_info->type != DiskCache)
976 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000977 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000978 else
979 {
cristyfd24a062012-01-02 14:46:34 +0000980 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000981 if ((MagickSizeType) count != length)
982 {
983 status=MagickFalse;
984 break;
985 }
986 }
987 clone_offset+=length;
988 }
989 }
990 length=clone_info->metacontent_extent;
991 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
992 for ( ; x < (ssize_t) clone_info->columns; x++)
993 {
994 /*
cristy9e0719b2011-12-29 03:45:45 +0000995 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000996 */
997 if (clone_info->type != DiskCache)
998 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
999 blob,length);
1000 else
1001 {
cristy208b1002011-08-07 18:51:50 +00001002 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001003 if ((MagickSizeType) count != length)
1004 {
1005 status=MagickFalse;
1006 break;
1007 }
1008 }
1009 clone_offset+=length;
1010 }
1011 }
1012 length=clone_info->metacontent_extent;
1013 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1014 for ( ; y < (ssize_t) clone_info->rows; y++)
1015 {
1016 /*
cristy9e0719b2011-12-29 03:45:45 +00001017 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001018 */
1019 for (x=0; x < (ssize_t) clone_info->columns; x++)
1020 {
1021 if (clone_info->type != DiskCache)
1022 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1023 blob,length);
1024 else
1025 {
1026 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1027 if ((MagickSizeType) count != length)
1028 {
1029 status=MagickFalse;
1030 break;
1031 }
1032 }
1033 clone_offset+=length;
1034 }
1035 }
1036 }
1037 if (clone_info->type == DiskCache)
1038 (void) ClosePixelCacheOnDisk(clone_info);
1039 if (cache_info->type == DiskCache)
1040 (void) ClosePixelCacheOnDisk(cache_info);
1041 blob=(unsigned char *) RelinquishMagickMemory(blob);
1042 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001043}
1044
1045static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1046 CacheInfo *cache_info,ExceptionInfo *exception)
1047{
cristy3dfccb22011-12-28 21:47:20 +00001048 PixelChannelMap
1049 *p,
1050 *q;
1051
cristy5a7fbfb2010-11-06 16:10:59 +00001052 if (cache_info->type == PingCache)
1053 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001054 p=cache_info->channel_map;
1055 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001056 if ((cache_info->columns == clone_info->columns) &&
1057 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001058 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001059 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001060 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001061 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1062 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001063}
1064
1065/*
1066%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1067% %
1068% %
1069% %
1070+ C l o n e P i x e l C a c h e M e t h o d s %
1071% %
1072% %
1073% %
1074%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1075%
1076% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1077% another.
1078%
1079% The format of the ClonePixelCacheMethods() method is:
1080%
1081% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1082%
1083% A description of each parameter follows:
1084%
1085% o clone: Specifies a pointer to a Cache structure.
1086%
1087% o cache: the pixel cache.
1088%
1089*/
cristya6577ff2011-09-02 19:54:26 +00001090MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001091{
1092 CacheInfo
1093 *cache_info,
1094 *source_info;
1095
1096 assert(clone != (Cache) NULL);
1097 source_info=(CacheInfo *) clone;
1098 assert(source_info->signature == MagickSignature);
1099 if (source_info->debug != MagickFalse)
1100 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1101 source_info->filename);
1102 assert(cache != (Cache) NULL);
1103 cache_info=(CacheInfo *) cache;
1104 assert(cache_info->signature == MagickSignature);
1105 source_info->methods=cache_info->methods;
1106}
1107
1108/*
1109%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1110% %
1111% %
1112% %
1113+ D e s t r o y I m a g e P i x e l C a c h e %
1114% %
1115% %
1116% %
1117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1118%
1119% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1120%
1121% The format of the DestroyImagePixelCache() method is:
1122%
1123% void DestroyImagePixelCache(Image *image)
1124%
1125% A description of each parameter follows:
1126%
1127% o image: the image.
1128%
1129*/
1130static void DestroyImagePixelCache(Image *image)
1131{
1132 assert(image != (Image *) NULL);
1133 assert(image->signature == MagickSignature);
1134 if (image->debug != MagickFalse)
1135 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1136 if (image->cache == (void *) NULL)
1137 return;
1138 image->cache=DestroyPixelCache(image->cache);
1139}
1140
1141/*
1142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1143% %
1144% %
1145% %
1146+ D e s t r o y I m a g e P i x e l s %
1147% %
1148% %
1149% %
1150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1151%
1152% DestroyImagePixels() deallocates memory associated with the pixel cache.
1153%
1154% The format of the DestroyImagePixels() method is:
1155%
1156% void DestroyImagePixels(Image *image)
1157%
1158% A description of each parameter follows:
1159%
1160% o image: the image.
1161%
1162*/
1163MagickExport void DestroyImagePixels(Image *image)
1164{
1165 CacheInfo
1166 *cache_info;
1167
1168 assert(image != (const Image *) NULL);
1169 assert(image->signature == MagickSignature);
1170 if (image->debug != MagickFalse)
1171 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1172 assert(image->cache != (Cache) NULL);
1173 cache_info=(CacheInfo *) image->cache;
1174 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001175 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1176 {
1177 cache_info->methods.destroy_pixel_handler(image);
1178 return;
1179 }
cristy2036f5c2010-09-19 21:18:17 +00001180 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001181}
1182
1183/*
1184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1185% %
1186% %
1187% %
1188+ D e s t r o y P i x e l C a c h e %
1189% %
1190% %
1191% %
1192%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1193%
1194% DestroyPixelCache() deallocates memory associated with the pixel cache.
1195%
1196% The format of the DestroyPixelCache() method is:
1197%
1198% Cache DestroyPixelCache(Cache cache)
1199%
1200% A description of each parameter follows:
1201%
1202% o cache: the pixel cache.
1203%
1204*/
1205
1206static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1207{
1208 switch (cache_info->type)
1209 {
1210 case MemoryCache:
1211 {
1212 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001213 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001214 cache_info->pixels);
1215 else
cristy4c08aed2011-07-01 19:47:50 +00001216 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001217 (size_t) cache_info->length);
1218 RelinquishMagickResource(MemoryResource,cache_info->length);
1219 break;
1220 }
1221 case MapCache:
1222 {
cristy4c08aed2011-07-01 19:47:50 +00001223 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001224 cache_info->length);
1225 RelinquishMagickResource(MapResource,cache_info->length);
1226 }
1227 case DiskCache:
1228 {
1229 if (cache_info->file != -1)
1230 (void) ClosePixelCacheOnDisk(cache_info);
1231 RelinquishMagickResource(DiskResource,cache_info->length);
1232 break;
1233 }
1234 default:
1235 break;
1236 }
1237 cache_info->type=UndefinedCache;
1238 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001239 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001240}
1241
cristya6577ff2011-09-02 19:54:26 +00001242MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001243{
1244 CacheInfo
1245 *cache_info;
1246
cristy3ed852e2009-09-05 21:47:34 +00001247 assert(cache != (Cache) NULL);
1248 cache_info=(CacheInfo *) cache;
1249 assert(cache_info->signature == MagickSignature);
1250 if (cache_info->debug != MagickFalse)
1251 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1252 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001253 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001254 cache_info->reference_count--;
1255 if (cache_info->reference_count != 0)
1256 {
cristyf84a1932010-01-03 18:00:18 +00001257 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001258 return((Cache) NULL);
1259 }
cristyf84a1932010-01-03 18:00:18 +00001260 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001261 if (cache_info->debug != MagickFalse)
1262 {
1263 char
1264 message[MaxTextExtent];
1265
cristyb51dff52011-05-19 16:55:47 +00001266 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001267 cache_info->filename);
1268 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1269 }
cristyc2e1bdd2009-09-10 23:43:34 +00001270 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1271 (cache_info->type != DiskCache)))
1272 RelinquishPixelCachePixels(cache_info);
1273 else
1274 {
1275 RelinquishPixelCachePixels(cache_info);
1276 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1277 }
cristy3ed852e2009-09-05 21:47:34 +00001278 *cache_info->cache_filename='\0';
1279 if (cache_info->nexus_info != (NexusInfo **) NULL)
1280 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1281 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001282 if (cache_info->random_info != (RandomInfo *) NULL)
1283 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001284 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1285 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1286 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1287 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001288 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001289 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001290 cache=(Cache) NULL;
1291 return(cache);
1292}
1293
1294/*
1295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1296% %
1297% %
1298% %
1299+ D e s t r o y P i x e l C a c h e N e x u s %
1300% %
1301% %
1302% %
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304%
1305% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1306%
1307% The format of the DestroyPixelCacheNexus() method is:
1308%
1309% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001310% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001311%
1312% A description of each parameter follows:
1313%
1314% o nexus_info: the nexus to destroy.
1315%
1316% o number_threads: the number of nexus threads.
1317%
1318*/
1319
1320static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1321{
1322 if (nexus_info->mapped == MagickFalse)
cristy7dc8ac52012-01-10 20:14:52 +00001323 (void) RelinquishAlignedMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001324 else
1325 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001326 nexus_info->cache=(Quantum *) NULL;
1327 nexus_info->pixels=(Quantum *) NULL;
1328 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001329 nexus_info->length=0;
1330 nexus_info->mapped=MagickFalse;
1331}
1332
cristya6577ff2011-09-02 19:54:26 +00001333MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001334 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001335{
cristybb503372010-05-27 20:51:26 +00001336 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001337 i;
1338
1339 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001340 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001341 {
cristy4c08aed2011-07-01 19:47:50 +00001342 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001343 RelinquishCacheNexusPixels(nexus_info[i]);
1344 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001345 }
cristye5f87c82012-02-14 12:44:17 +00001346 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristyb41ee102010-10-04 16:46:15 +00001347 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001348 return(nexus_info);
1349}
1350
1351/*
1352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353% %
1354% %
1355% %
cristy4c08aed2011-07-01 19:47:50 +00001356% 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 +00001357% %
1358% %
1359% %
1360%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1361%
cristy4c08aed2011-07-01 19:47:50 +00001362% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1363% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1364% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001365%
cristy4c08aed2011-07-01 19:47:50 +00001366% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001367%
cristy4c08aed2011-07-01 19:47:50 +00001368% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001369%
1370% A description of each parameter follows:
1371%
1372% o image: the image.
1373%
1374*/
cristy4c08aed2011-07-01 19:47:50 +00001375MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001376{
1377 CacheInfo
1378 *cache_info;
1379
cristy5c9e6f22010-09-17 17:31:01 +00001380 const int
1381 id = GetOpenMPThreadId();
1382
cristy4c08aed2011-07-01 19:47:50 +00001383 void
1384 *metacontent;
1385
cristye7cc7cf2010-09-21 13:26:47 +00001386 assert(image != (const Image *) NULL);
1387 assert(image->signature == MagickSignature);
1388 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001389 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001390 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001391 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1392 (GetAuthenticMetacontentFromHandler) NULL)
1393 {
1394 metacontent=cache_info->methods.
1395 get_authentic_metacontent_from_handler(image);
1396 return(metacontent);
1397 }
cristy6ebe97c2010-07-03 01:17:28 +00001398 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001399 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1400 cache_info->nexus_info[id]);
1401 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001402}
1403
1404/*
1405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406% %
1407% %
1408% %
cristy4c08aed2011-07-01 19:47:50 +00001409+ 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 +00001410% %
1411% %
1412% %
1413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414%
cristy4c08aed2011-07-01 19:47:50 +00001415% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1416% with the last call to QueueAuthenticPixelsCache() or
1417% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001418%
cristy4c08aed2011-07-01 19:47:50 +00001419% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001420%
cristy4c08aed2011-07-01 19:47:50 +00001421% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001422%
1423% A description of each parameter follows:
1424%
1425% o image: the image.
1426%
1427*/
cristy4c08aed2011-07-01 19:47:50 +00001428static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001429{
1430 CacheInfo
1431 *cache_info;
1432
cristy2036f5c2010-09-19 21:18:17 +00001433 const int
1434 id = GetOpenMPThreadId();
1435
cristy4c08aed2011-07-01 19:47:50 +00001436 void
1437 *metacontent;
1438
cristy3ed852e2009-09-05 21:47:34 +00001439 assert(image != (const Image *) NULL);
1440 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001441 assert(image->cache != (Cache) NULL);
1442 cache_info=(CacheInfo *) image->cache;
1443 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001444 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001445 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1446 cache_info->nexus_info[id]);
1447 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001448}
1449
1450/*
1451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1452% %
1453% %
1454% %
1455+ 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 %
1456% %
1457% %
1458% %
1459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1460%
1461% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1462% disk pixel cache as defined by the geometry parameters. A pointer to the
1463% pixels is returned if the pixels are transferred, otherwise a NULL is
1464% returned.
1465%
1466% The format of the GetAuthenticPixelCacheNexus() method is:
1467%
cristy4c08aed2011-07-01 19:47:50 +00001468% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001469% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001470% NexusInfo *nexus_info,ExceptionInfo *exception)
1471%
1472% A description of each parameter follows:
1473%
1474% o image: the image.
1475%
1476% o x,y,columns,rows: These values define the perimeter of a region of
1477% pixels.
1478%
1479% o nexus_info: the cache nexus to return.
1480%
1481% o exception: return any errors or warnings in this structure.
1482%
1483*/
1484
cristy4c08aed2011-07-01 19:47:50 +00001485static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001486 NexusInfo *nexus_info)
1487{
cristy4c08aed2011-07-01 19:47:50 +00001488 MagickBooleanType
1489 status;
1490
cristy3ed852e2009-09-05 21:47:34 +00001491 MagickOffsetType
1492 offset;
1493
cristy73724512010-04-12 14:43:14 +00001494 if (cache_info->type == PingCache)
1495 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001496 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1497 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001498 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001499 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001500 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001501}
1502
cristya6577ff2011-09-02 19:54:26 +00001503MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001504 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001505 NexusInfo *nexus_info,ExceptionInfo *exception)
1506{
1507 CacheInfo
1508 *cache_info;
1509
cristy4c08aed2011-07-01 19:47:50 +00001510 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001511 *q;
cristy3ed852e2009-09-05 21:47:34 +00001512
1513 /*
1514 Transfer pixels from the cache.
1515 */
1516 assert(image != (Image *) NULL);
1517 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001518 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1519 exception);
cristyacd2ed22011-08-30 01:44:23 +00001520 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001521 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001522 cache_info=(CacheInfo *) image->cache;
1523 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001524 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001525 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001526 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001527 return((Quantum *) NULL);
1528 if (cache_info->metacontent_extent != 0)
1529 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1530 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001531 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001532}
1533
1534/*
1535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536% %
1537% %
1538% %
1539+ 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 %
1540% %
1541% %
1542% %
1543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1544%
1545% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1546% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1547%
1548% The format of the GetAuthenticPixelsFromCache() method is:
1549%
cristy4c08aed2011-07-01 19:47:50 +00001550% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001551%
1552% A description of each parameter follows:
1553%
1554% o image: the image.
1555%
1556*/
cristy4c08aed2011-07-01 19:47:50 +00001557static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001558{
1559 CacheInfo
1560 *cache_info;
1561
cristy5c9e6f22010-09-17 17:31:01 +00001562 const int
1563 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001564
cristye7cc7cf2010-09-21 13:26:47 +00001565 assert(image != (const Image *) NULL);
1566 assert(image->signature == MagickSignature);
1567 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001568 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001569 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001570 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001571 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001572}
1573
1574/*
1575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1576% %
1577% %
1578% %
1579% G e t A u t h e n t i c P i x e l Q u e u e %
1580% %
1581% %
1582% %
1583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1584%
cristy4c08aed2011-07-01 19:47:50 +00001585% GetAuthenticPixelQueue() returns the authentic pixels associated
1586% corresponding with the last call to QueueAuthenticPixels() or
1587% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001588%
1589% The format of the GetAuthenticPixelQueue() method is:
1590%
cristy4c08aed2011-07-01 19:47:50 +00001591% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001592%
1593% A description of each parameter follows:
1594%
1595% o image: the image.
1596%
1597*/
cristy4c08aed2011-07-01 19:47:50 +00001598MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001599{
1600 CacheInfo
1601 *cache_info;
1602
cristy2036f5c2010-09-19 21:18:17 +00001603 const int
1604 id = GetOpenMPThreadId();
1605
cristy3ed852e2009-09-05 21:47:34 +00001606 assert(image != (const Image *) NULL);
1607 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001608 assert(image->cache != (Cache) NULL);
1609 cache_info=(CacheInfo *) image->cache;
1610 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001611 if (cache_info->methods.get_authentic_pixels_from_handler !=
1612 (GetAuthenticPixelsFromHandler) NULL)
1613 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001614 assert(id < (int) cache_info->number_threads);
1615 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001616}
1617
1618/*
1619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1620% %
1621% %
1622% %
1623% G e t A u t h e n t i c P i x e l s %
1624% %
1625% %
cristy4c08aed2011-07-01 19:47:50 +00001626% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001627%
1628% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001629% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001630% representing the region is returned, otherwise NULL is returned.
1631%
1632% The returned pointer may point to a temporary working copy of the pixels
1633% or it may point to the original pixels in memory. Performance is maximized
1634% if the selected region is part of one row, or one or more full rows, since
1635% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001636% if the image is in memory, or in a memory-mapped file. The returned pointer
1637% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001638%
1639% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001640% Quantum. If the image has corresponding metacontent,call
1641% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1642% meta-content corresponding to the region. Once the Quantum array has
1643% been updated, the changes must be saved back to the underlying image using
1644% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001645%
1646% The format of the GetAuthenticPixels() method is:
1647%
cristy4c08aed2011-07-01 19:47:50 +00001648% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001649% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001650% ExceptionInfo *exception)
1651%
1652% A description of each parameter follows:
1653%
1654% o image: the image.
1655%
1656% o x,y,columns,rows: These values define the perimeter of a region of
1657% pixels.
1658%
1659% o exception: return any errors or warnings in this structure.
1660%
1661*/
cristy4c08aed2011-07-01 19:47:50 +00001662MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001663 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001664 ExceptionInfo *exception)
1665{
1666 CacheInfo
1667 *cache_info;
1668
cristy2036f5c2010-09-19 21:18:17 +00001669 const int
1670 id = GetOpenMPThreadId();
1671
cristy4c08aed2011-07-01 19:47:50 +00001672 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001673 *q;
cristy4c08aed2011-07-01 19:47:50 +00001674
cristy3ed852e2009-09-05 21:47:34 +00001675 assert(image != (Image *) NULL);
1676 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001677 assert(image->cache != (Cache) NULL);
1678 cache_info=(CacheInfo *) image->cache;
1679 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001680 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001681 (GetAuthenticPixelsHandler) NULL)
1682 {
cristyacd2ed22011-08-30 01:44:23 +00001683 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1684 exception);
1685 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001686 }
cristy2036f5c2010-09-19 21:18:17 +00001687 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001688 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001689 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001690 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001691}
1692
1693/*
1694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1695% %
1696% %
1697% %
1698+ G e t A u t h e n t i c P i x e l s C a c h e %
1699% %
1700% %
1701% %
1702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703%
1704% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1705% as defined by the geometry parameters. A pointer to the pixels is returned
1706% if the pixels are transferred, otherwise a NULL is returned.
1707%
1708% The format of the GetAuthenticPixelsCache() method is:
1709%
cristy4c08aed2011-07-01 19:47:50 +00001710% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001711% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001712% ExceptionInfo *exception)
1713%
1714% A description of each parameter follows:
1715%
1716% o image: the image.
1717%
1718% o x,y,columns,rows: These values define the perimeter of a region of
1719% pixels.
1720%
1721% o exception: return any errors or warnings in this structure.
1722%
1723*/
cristy4c08aed2011-07-01 19:47:50 +00001724static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001725 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001726 ExceptionInfo *exception)
1727{
1728 CacheInfo
1729 *cache_info;
1730
cristy5c9e6f22010-09-17 17:31:01 +00001731 const int
1732 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001733
cristy4c08aed2011-07-01 19:47:50 +00001734 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001735 *q;
cristy4c08aed2011-07-01 19:47:50 +00001736
cristye7cc7cf2010-09-21 13:26:47 +00001737 assert(image != (const Image *) NULL);
1738 assert(image->signature == MagickSignature);
1739 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001740 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001741 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001742 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001743 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001744 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001745 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001746 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001747 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001748}
1749
1750/*
1751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1752% %
1753% %
1754% %
1755+ G e t I m a g e E x t e n t %
1756% %
1757% %
1758% %
1759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760%
cristy4c08aed2011-07-01 19:47:50 +00001761% GetImageExtent() returns the extent of the pixels associated corresponding
1762% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001763%
1764% The format of the GetImageExtent() method is:
1765%
1766% MagickSizeType GetImageExtent(const Image *image)
1767%
1768% A description of each parameter follows:
1769%
1770% o image: the image.
1771%
1772*/
1773MagickExport MagickSizeType GetImageExtent(const Image *image)
1774{
1775 CacheInfo
1776 *cache_info;
1777
cristy5c9e6f22010-09-17 17:31:01 +00001778 const int
1779 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001780
cristy3ed852e2009-09-05 21:47:34 +00001781 assert(image != (Image *) NULL);
1782 assert(image->signature == MagickSignature);
1783 if (image->debug != MagickFalse)
1784 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1785 assert(image->cache != (Cache) NULL);
1786 cache_info=(CacheInfo *) image->cache;
1787 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001788 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001789 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001790}
1791
1792/*
1793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1794% %
1795% %
1796% %
1797+ G e t I m a g e P i x e l C a c h e %
1798% %
1799% %
1800% %
1801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802%
1803% GetImagePixelCache() ensures that there is only a single reference to the
1804% pixel cache to be modified, updating the provided cache pointer to point to
1805% a clone of the original pixel cache if necessary.
1806%
1807% The format of the GetImagePixelCache method is:
1808%
1809% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1810% ExceptionInfo *exception)
1811%
1812% A description of each parameter follows:
1813%
1814% o image: the image.
1815%
1816% o clone: any value other than MagickFalse clones the cache pixels.
1817%
1818% o exception: return any errors or warnings in this structure.
1819%
1820*/
cristyaf894d72011-08-06 23:03:10 +00001821
cristy3ed852e2009-09-05 21:47:34 +00001822static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1823{
1824 CacheInfo
1825 *cache_info;
1826
cristy9e0719b2011-12-29 03:45:45 +00001827 PixelChannelMap
1828 *p,
1829 *q;
1830
cristy3ed852e2009-09-05 21:47:34 +00001831 /*
1832 Does the image match the pixel cache morphology?
1833 */
1834 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001835 p=image->channel_map;
1836 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001837 if ((image->storage_class != cache_info->storage_class) ||
1838 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001839 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001840 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001841 (image->columns != cache_info->columns) ||
1842 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001843 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001844 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001845 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001846 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1847 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1848 return(MagickFalse);
1849 return(MagickTrue);
1850}
1851
cristycd01fae2011-08-06 23:52:42 +00001852static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1853 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001854{
1855 CacheInfo
1856 *cache_info;
1857
cristy3ed852e2009-09-05 21:47:34 +00001858 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001859 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001860 status;
1861
cristy50a10922010-02-15 18:35:25 +00001862 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001863 cpu_throttle = 0,
1864 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001865 time_limit = 0;
1866
cristy1ea34962010-07-01 19:49:21 +00001867 static time_t
cristy208b1002011-08-07 18:51:50 +00001868 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001869
cristyc4f9f132010-03-04 18:50:01 +00001870 status=MagickTrue;
1871 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001872 if (cpu_throttle == 0)
1873 {
1874 char
1875 *limit;
1876
1877 /*
1878 Set CPU throttle in milleseconds.
1879 */
1880 cpu_throttle=MagickResourceInfinity;
1881 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1882 if (limit == (char *) NULL)
1883 limit=GetPolicyValue("throttle");
1884 if (limit != (char *) NULL)
1885 {
1886 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1887 limit=DestroyString(limit);
1888 }
1889 }
1890 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1891 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001892 if (time_limit == 0)
1893 {
cristy6ebe97c2010-07-03 01:17:28 +00001894 /*
1895 Set the exire time in seconds.
1896 */
cristy1ea34962010-07-01 19:49:21 +00001897 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001898 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001899 }
1900 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001901 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001902 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001903 assert(image->cache != (Cache) NULL);
1904 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001905 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001906 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001907 {
cristyceb55ee2010-11-06 16:05:49 +00001908 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001909 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001910 {
cristyceb55ee2010-11-06 16:05:49 +00001911 Image
1912 clone_image;
1913
1914 CacheInfo
1915 *clone_info;
1916
1917 /*
1918 Clone pixel cache.
1919 */
1920 clone_image=(*image);
1921 clone_image.semaphore=AllocateSemaphoreInfo();
1922 clone_image.reference_count=1;
1923 clone_image.cache=ClonePixelCache(cache_info);
1924 clone_info=(CacheInfo *) clone_image.cache;
1925 status=OpenPixelCache(&clone_image,IOMode,exception);
1926 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001927 {
cristy5a7fbfb2010-11-06 16:10:59 +00001928 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001929 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001930 if (status != MagickFalse)
1931 {
cristy979bf772011-08-08 00:04:15 +00001932 if (cache_info->mode == ReadMode)
1933 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001934 destroy=MagickTrue;
1935 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001936 }
1937 }
cristyceb55ee2010-11-06 16:05:49 +00001938 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001939 }
cristyceb55ee2010-11-06 16:05:49 +00001940 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001941 }
cristy4320e0e2009-09-10 15:00:08 +00001942 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001943 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001944 if (status != MagickFalse)
1945 {
1946 /*
1947 Ensure the image matches the pixel cache morphology.
1948 */
1949 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001950 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001951 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001952 {
1953 status=OpenPixelCache(image,IOMode,exception);
1954 cache_info=(CacheInfo *) image->cache;
1955 if (cache_info->type == DiskCache)
1956 (void) ClosePixelCacheOnDisk(cache_info);
1957 }
cristy3ed852e2009-09-05 21:47:34 +00001958 }
cristyf84a1932010-01-03 18:00:18 +00001959 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001960 if (status == MagickFalse)
1961 return((Cache) NULL);
1962 return(image->cache);
1963}
1964
1965/*
1966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1967% %
1968% %
1969% %
1970% G e t O n e A u t h e n t i c P i x e l %
1971% %
1972% %
1973% %
1974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1975%
1976% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1977% location. The image background color is returned if an error occurs.
1978%
1979% The format of the GetOneAuthenticPixel() method is:
1980%
cristybb503372010-05-27 20:51:26 +00001981% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00001982% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001983%
1984% A description of each parameter follows:
1985%
1986% o image: the image.
1987%
1988% o x,y: These values define the location of the pixel to return.
1989%
1990% o pixel: return a pixel at the specified (x,y) location.
1991%
1992% o exception: return any errors or warnings in this structure.
1993%
1994*/
cristyacbbb7c2010-06-30 18:56:48 +00001995MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00001996 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001997{
1998 CacheInfo
1999 *cache_info;
2000
cristy4c08aed2011-07-01 19:47:50 +00002001 register Quantum
2002 *q;
cristy2036f5c2010-09-19 21:18:17 +00002003
cristy2ed42f62011-10-02 19:49:57 +00002004 register ssize_t
2005 i;
2006
cristy3ed852e2009-09-05 21:47:34 +00002007 assert(image != (Image *) NULL);
2008 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002009 assert(image->cache != (Cache) NULL);
2010 cache_info=(CacheInfo *) image->cache;
2011 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002012 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002013 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2014 (GetOneAuthenticPixelFromHandler) NULL)
2015 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2016 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002017 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2018 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002019 {
cristy9e0719b2011-12-29 03:45:45 +00002020 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2021 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2022 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2023 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2024 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002025 return(MagickFalse);
2026 }
2027 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2028 {
2029 PixelChannel
2030 channel;
2031
cristye2a912b2011-12-05 20:02:07 +00002032 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002033 pixel[channel]=q[i];
2034 }
cristy2036f5c2010-09-19 21:18:17 +00002035 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002036}
2037
2038/*
2039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2040% %
2041% %
2042% %
2043+ 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 %
2044% %
2045% %
2046% %
2047%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2048%
2049% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2050% location. The image background color is returned if an error occurs.
2051%
2052% The format of the GetOneAuthenticPixelFromCache() method is:
2053%
2054% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002055% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002056% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002057%
2058% A description of each parameter follows:
2059%
2060% o image: the image.
2061%
2062% o x,y: These values define the location of the pixel to return.
2063%
2064% o pixel: return a pixel at the specified (x,y) location.
2065%
2066% o exception: return any errors or warnings in this structure.
2067%
2068*/
2069static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002070 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002071{
cristy098f78c2010-09-23 17:28:44 +00002072 CacheInfo
2073 *cache_info;
2074
2075 const int
2076 id = GetOpenMPThreadId();
2077
cristy4c08aed2011-07-01 19:47:50 +00002078 register Quantum
2079 *q;
cristy3ed852e2009-09-05 21:47:34 +00002080
cristy2ed42f62011-10-02 19:49:57 +00002081 register ssize_t
2082 i;
2083
cristy0158a4b2010-09-20 13:59:45 +00002084 assert(image != (const Image *) NULL);
2085 assert(image->signature == MagickSignature);
2086 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002087 cache_info=(CacheInfo *) image->cache;
2088 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002089 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002090 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002091 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2092 exception);
2093 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002094 {
cristy9e0719b2011-12-29 03:45:45 +00002095 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2096 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2097 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2098 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2099 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002100 return(MagickFalse);
2101 }
2102 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2103 {
2104 PixelChannel
2105 channel;
2106
cristye2a912b2011-12-05 20:02:07 +00002107 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002108 pixel[channel]=q[i];
2109 }
cristy3ed852e2009-09-05 21:47:34 +00002110 return(MagickTrue);
2111}
2112
2113/*
2114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2115% %
2116% %
2117% %
cristy3ed852e2009-09-05 21:47:34 +00002118% G e t O n e V i r t u a l P i x e l %
2119% %
2120% %
2121% %
2122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2123%
2124% GetOneVirtualPixel() returns a single virtual pixel at the specified
2125% (x,y) location. The image background color is returned if an error occurs.
2126% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2127%
2128% The format of the GetOneVirtualPixel() method is:
2129%
cristybb503372010-05-27 20:51:26 +00002130% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002131% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002132%
2133% A description of each parameter follows:
2134%
2135% o image: the image.
2136%
2137% o x,y: These values define the location of the pixel to return.
2138%
2139% o pixel: return a pixel at the specified (x,y) location.
2140%
2141% o exception: return any errors or warnings in this structure.
2142%
2143*/
2144MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002145 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002146{
cristy3ed852e2009-09-05 21:47:34 +00002147 CacheInfo
2148 *cache_info;
2149
cristy0158a4b2010-09-20 13:59:45 +00002150 const int
2151 id = GetOpenMPThreadId();
2152
cristy4c08aed2011-07-01 19:47:50 +00002153 const Quantum
2154 *p;
cristy2036f5c2010-09-19 21:18:17 +00002155
cristy2ed42f62011-10-02 19:49:57 +00002156 register ssize_t
2157 i;
2158
cristy3ed852e2009-09-05 21:47:34 +00002159 assert(image != (const Image *) NULL);
2160 assert(image->signature == MagickSignature);
2161 assert(image->cache != (Cache) NULL);
2162 cache_info=(CacheInfo *) image->cache;
2163 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002164 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002165 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2166 (GetOneVirtualPixelFromHandler) NULL)
2167 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2168 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002169 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002170 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002171 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002172 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002173 {
cristy9e0719b2011-12-29 03:45:45 +00002174 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2175 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2176 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2177 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2178 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002179 return(MagickFalse);
2180 }
2181 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2182 {
2183 PixelChannel
2184 channel;
2185
cristye2a912b2011-12-05 20:02:07 +00002186 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002187 pixel[channel]=p[i];
2188 }
cristy2036f5c2010-09-19 21:18:17 +00002189 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002190}
2191
2192/*
2193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2194% %
2195% %
2196% %
2197+ 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 %
2198% %
2199% %
2200% %
2201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2202%
2203% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2204% specified (x,y) location. The image background color is returned if an
2205% error occurs.
2206%
2207% The format of the GetOneVirtualPixelFromCache() method is:
2208%
2209% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002210% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002211% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002212%
2213% A description of each parameter follows:
2214%
2215% o image: the image.
2216%
2217% o virtual_pixel_method: the virtual pixel method.
2218%
2219% o x,y: These values define the location of the pixel to return.
2220%
2221% o pixel: return a pixel at the specified (x,y) location.
2222%
2223% o exception: return any errors or warnings in this structure.
2224%
2225*/
2226static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002227 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002228 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002229{
cristy0158a4b2010-09-20 13:59:45 +00002230 CacheInfo
2231 *cache_info;
2232
2233 const int
2234 id = GetOpenMPThreadId();
2235
cristy4c08aed2011-07-01 19:47:50 +00002236 const Quantum
2237 *p;
cristy3ed852e2009-09-05 21:47:34 +00002238
cristy2ed42f62011-10-02 19:49:57 +00002239 register ssize_t
2240 i;
2241
cristye7cc7cf2010-09-21 13:26:47 +00002242 assert(image != (const Image *) NULL);
2243 assert(image->signature == MagickSignature);
2244 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002245 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002246 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002247 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002248 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002249 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002250 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002251 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002252 {
cristy9e0719b2011-12-29 03:45:45 +00002253 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2254 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2255 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2256 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2257 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002258 return(MagickFalse);
2259 }
2260 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2261 {
2262 PixelChannel
2263 channel;
2264
cristye2a912b2011-12-05 20:02:07 +00002265 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002266 pixel[channel]=p[i];
2267 }
cristy3ed852e2009-09-05 21:47:34 +00002268 return(MagickTrue);
2269}
2270
2271/*
2272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273% %
2274% %
2275% %
cristy3aa93752011-12-18 15:54:24 +00002276% G e t O n e V i r t u a l P i x e l I n f o %
2277% %
2278% %
2279% %
2280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281%
2282% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2283% location. The image background color is returned if an error occurs. If
2284% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2285%
2286% The format of the GetOneVirtualPixelInfo() method is:
2287%
2288% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2289% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2290% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2291%
2292% A description of each parameter follows:
2293%
2294% o image: the image.
2295%
2296% o virtual_pixel_method: the virtual pixel method.
2297%
2298% o x,y: these values define the location of the pixel to return.
2299%
2300% o pixel: return a pixel at the specified (x,y) location.
2301%
2302% o exception: return any errors or warnings in this structure.
2303%
2304*/
2305MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2306 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2307 PixelInfo *pixel,ExceptionInfo *exception)
2308{
2309 CacheInfo
2310 *cache_info;
2311
2312 const int
2313 id = GetOpenMPThreadId();
2314
2315 register const Quantum
2316 *p;
2317
2318 assert(image != (const Image *) NULL);
2319 assert(image->signature == MagickSignature);
2320 assert(image->cache != (Cache) NULL);
2321 cache_info=(CacheInfo *) image->cache;
2322 assert(cache_info->signature == MagickSignature);
2323 assert(id < (int) cache_info->number_threads);
2324 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2325 cache_info->nexus_info[id],exception);
2326 GetPixelInfo(image,pixel);
2327 if (p == (const Quantum *) NULL)
2328 return(MagickFalse);
2329 GetPixelInfoPixel(image,p,pixel);
2330 return(MagickTrue);
2331}
2332
2333/*
2334%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2335% %
2336% %
2337% %
cristy3ed852e2009-09-05 21:47:34 +00002338+ G e t P i x e l C a c h e C o l o r s p a c e %
2339% %
2340% %
2341% %
2342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2343%
2344% GetPixelCacheColorspace() returns the class type of the pixel cache.
2345%
2346% The format of the GetPixelCacheColorspace() method is:
2347%
2348% Colorspace GetPixelCacheColorspace(Cache cache)
2349%
2350% A description of each parameter follows:
2351%
2352% o cache: the pixel cache.
2353%
2354*/
cristya6577ff2011-09-02 19:54:26 +00002355MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002356{
2357 CacheInfo
2358 *cache_info;
2359
2360 assert(cache != (Cache) NULL);
2361 cache_info=(CacheInfo *) cache;
2362 assert(cache_info->signature == MagickSignature);
2363 if (cache_info->debug != MagickFalse)
2364 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2365 cache_info->filename);
2366 return(cache_info->colorspace);
2367}
2368
2369/*
2370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2371% %
2372% %
2373% %
2374+ G e t P i x e l C a c h e M e t h o d s %
2375% %
2376% %
2377% %
2378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2379%
2380% GetPixelCacheMethods() initializes the CacheMethods structure.
2381%
2382% The format of the GetPixelCacheMethods() method is:
2383%
2384% void GetPixelCacheMethods(CacheMethods *cache_methods)
2385%
2386% A description of each parameter follows:
2387%
2388% o cache_methods: Specifies a pointer to a CacheMethods structure.
2389%
2390*/
cristya6577ff2011-09-02 19:54:26 +00002391MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002392{
2393 assert(cache_methods != (CacheMethods *) NULL);
2394 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2395 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2396 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002397 cache_methods->get_virtual_metacontent_from_handler=
2398 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002399 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2400 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002401 cache_methods->get_authentic_metacontent_from_handler=
2402 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002403 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2404 cache_methods->get_one_authentic_pixel_from_handler=
2405 GetOneAuthenticPixelFromCache;
2406 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2407 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2408 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2409}
2410
2411/*
2412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2413% %
2414% %
2415% %
2416+ G e t P i x e l C a c h e N e x u s E x t e n t %
2417% %
2418% %
2419% %
2420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2421%
cristy4c08aed2011-07-01 19:47:50 +00002422% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2423% corresponding with the last call to SetPixelCacheNexusPixels() or
2424% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002425%
2426% The format of the GetPixelCacheNexusExtent() method is:
2427%
2428% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2429% NexusInfo *nexus_info)
2430%
2431% A description of each parameter follows:
2432%
2433% o nexus_info: the nexus info.
2434%
2435*/
cristya6577ff2011-09-02 19:54:26 +00002436MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002437 NexusInfo *nexus_info)
2438{
2439 CacheInfo
2440 *cache_info;
2441
2442 MagickSizeType
2443 extent;
2444
cristy9f027d12011-09-21 01:17:17 +00002445 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002446 cache_info=(CacheInfo *) cache;
2447 assert(cache_info->signature == MagickSignature);
2448 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2449 if (extent == 0)
2450 return((MagickSizeType) cache_info->columns*cache_info->rows);
2451 return(extent);
2452}
2453
2454/*
2455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2456% %
2457% %
2458% %
cristy4c08aed2011-07-01 19:47:50 +00002459+ 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 +00002460% %
2461% %
2462% %
2463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2464%
cristy4c08aed2011-07-01 19:47:50 +00002465% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2466% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002467%
cristy4c08aed2011-07-01 19:47:50 +00002468% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002469%
cristy4c08aed2011-07-01 19:47:50 +00002470% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002471% NexusInfo *nexus_info)
2472%
2473% A description of each parameter follows:
2474%
2475% o cache: the pixel cache.
2476%
cristy4c08aed2011-07-01 19:47:50 +00002477% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002478%
2479*/
cristya6577ff2011-09-02 19:54:26 +00002480MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002481 NexusInfo *nexus_info)
2482{
2483 CacheInfo
2484 *cache_info;
2485
cristy9f027d12011-09-21 01:17:17 +00002486 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002487 cache_info=(CacheInfo *) cache;
2488 assert(cache_info->signature == MagickSignature);
2489 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002490 return((void *) NULL);
2491 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002492}
2493
2494/*
2495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2496% %
2497% %
2498% %
2499+ G e t P i x e l C a c h e N e x u s P i x e l s %
2500% %
2501% %
2502% %
2503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2504%
2505% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2506% cache nexus.
2507%
2508% The format of the GetPixelCacheNexusPixels() method is:
2509%
cristy4c08aed2011-07-01 19:47:50 +00002510% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002511% NexusInfo *nexus_info)
2512%
2513% A description of each parameter follows:
2514%
2515% o cache: the pixel cache.
2516%
2517% o nexus_info: the cache nexus to return the pixels.
2518%
2519*/
cristya6577ff2011-09-02 19:54:26 +00002520MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002521 NexusInfo *nexus_info)
2522{
2523 CacheInfo
2524 *cache_info;
2525
cristy9f027d12011-09-21 01:17:17 +00002526 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002527 cache_info=(CacheInfo *) cache;
2528 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002529 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002530 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002531 return(nexus_info->pixels);
2532}
2533
2534/*
2535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2536% %
2537% %
2538% %
cristy056ba772010-01-02 23:33:54 +00002539+ G e t P i x e l C a c h e P i x e l s %
2540% %
2541% %
2542% %
2543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2544%
2545% GetPixelCachePixels() returns the pixels associated with the specified image.
2546%
2547% The format of the GetPixelCachePixels() method is:
2548%
cristyf84a1932010-01-03 18:00:18 +00002549% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2550% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002551%
2552% A description of each parameter follows:
2553%
2554% o image: the image.
2555%
2556% o length: the pixel cache length.
2557%
cristyf84a1932010-01-03 18:00:18 +00002558% o exception: return any errors or warnings in this structure.
2559%
cristy056ba772010-01-02 23:33:54 +00002560*/
cristyd1dd6e42011-09-04 01:46:08 +00002561MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002562 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002563{
2564 CacheInfo
2565 *cache_info;
2566
2567 assert(image != (const Image *) NULL);
2568 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002569 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002570 assert(length != (MagickSizeType *) NULL);
2571 assert(exception != (ExceptionInfo *) NULL);
2572 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002573 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002574 assert(cache_info->signature == MagickSignature);
2575 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002576 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002577 return((void *) NULL);
2578 *length=cache_info->length;
2579 return((void *) cache_info->pixels);
2580}
2581
2582/*
2583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2584% %
2585% %
2586% %
cristyb32b90a2009-09-07 21:45:48 +00002587+ 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 +00002588% %
2589% %
2590% %
2591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2592%
2593% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2594%
2595% The format of the GetPixelCacheStorageClass() method is:
2596%
2597% ClassType GetPixelCacheStorageClass(Cache cache)
2598%
2599% A description of each parameter follows:
2600%
2601% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2602%
2603% o cache: the pixel cache.
2604%
2605*/
cristya6577ff2011-09-02 19:54:26 +00002606MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002607{
2608 CacheInfo
2609 *cache_info;
2610
2611 assert(cache != (Cache) NULL);
2612 cache_info=(CacheInfo *) cache;
2613 assert(cache_info->signature == MagickSignature);
2614 if (cache_info->debug != MagickFalse)
2615 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2616 cache_info->filename);
2617 return(cache_info->storage_class);
2618}
2619
2620/*
2621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2622% %
2623% %
2624% %
cristyb32b90a2009-09-07 21:45:48 +00002625+ G e t P i x e l C a c h e T i l e S i z e %
2626% %
2627% %
2628% %
2629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630%
2631% GetPixelCacheTileSize() returns the pixel cache tile size.
2632%
2633% The format of the GetPixelCacheTileSize() method is:
2634%
cristybb503372010-05-27 20:51:26 +00002635% void GetPixelCacheTileSize(const Image *image,size_t *width,
2636% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002637%
2638% A description of each parameter follows:
2639%
2640% o image: the image.
2641%
2642% o width: the optimize cache tile width in pixels.
2643%
2644% o height: the optimize cache tile height in pixels.
2645%
2646*/
cristya6577ff2011-09-02 19:54:26 +00002647MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002648 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002649{
cristy4c08aed2011-07-01 19:47:50 +00002650 CacheInfo
2651 *cache_info;
2652
cristyb32b90a2009-09-07 21:45:48 +00002653 assert(image != (Image *) NULL);
2654 assert(image->signature == MagickSignature);
2655 if (image->debug != MagickFalse)
2656 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002657 cache_info=(CacheInfo *) image->cache;
2658 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002659 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002660 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002661 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002662 *height=(*width);
2663}
2664
2665/*
2666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2667% %
2668% %
2669% %
2670+ G e t P i x e l C a c h e T y p e %
2671% %
2672% %
2673% %
2674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675%
2676% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2677%
2678% The format of the GetPixelCacheType() method is:
2679%
2680% CacheType GetPixelCacheType(const Image *image)
2681%
2682% A description of each parameter follows:
2683%
2684% o image: the image.
2685%
2686*/
cristya6577ff2011-09-02 19:54:26 +00002687MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002688{
2689 CacheInfo
2690 *cache_info;
2691
2692 assert(image != (Image *) NULL);
2693 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002694 assert(image->cache != (Cache) NULL);
2695 cache_info=(CacheInfo *) image->cache;
2696 assert(cache_info->signature == MagickSignature);
2697 return(cache_info->type);
2698}
2699
2700/*
2701%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2702% %
2703% %
2704% %
cristy3ed852e2009-09-05 21:47:34 +00002705+ 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 %
2706% %
2707% %
2708% %
2709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2710%
2711% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2712% pixel cache. A virtual pixel is any pixel access that is outside the
2713% boundaries of the image cache.
2714%
2715% The format of the GetPixelCacheVirtualMethod() method is:
2716%
2717% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2718%
2719% A description of each parameter follows:
2720%
2721% o image: the image.
2722%
2723*/
cristyd1dd6e42011-09-04 01:46:08 +00002724MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002725{
2726 CacheInfo
2727 *cache_info;
2728
2729 assert(image != (Image *) NULL);
2730 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002731 assert(image->cache != (Cache) NULL);
2732 cache_info=(CacheInfo *) image->cache;
2733 assert(cache_info->signature == MagickSignature);
2734 return(cache_info->virtual_pixel_method);
2735}
2736
2737/*
2738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2739% %
2740% %
2741% %
cristy4c08aed2011-07-01 19:47:50 +00002742+ 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 +00002743% %
2744% %
2745% %
2746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2747%
cristy4c08aed2011-07-01 19:47:50 +00002748% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2749% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002750%
cristy4c08aed2011-07-01 19:47:50 +00002751% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002752%
cristy4c08aed2011-07-01 19:47:50 +00002753% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002754%
2755% A description of each parameter follows:
2756%
2757% o image: the image.
2758%
2759*/
cristy4c08aed2011-07-01 19:47:50 +00002760static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002761{
2762 CacheInfo
2763 *cache_info;
2764
cristy5c9e6f22010-09-17 17:31:01 +00002765 const int
2766 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002767
cristy4c08aed2011-07-01 19:47:50 +00002768 const void
2769 *metacontent;
2770
cristye7cc7cf2010-09-21 13:26:47 +00002771 assert(image != (const Image *) NULL);
2772 assert(image->signature == MagickSignature);
2773 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002774 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002775 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002776 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002777 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2778 cache_info->nexus_info[id]);
2779 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002780}
2781
2782/*
2783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2784% %
2785% %
2786% %
cristy4c08aed2011-07-01 19:47:50 +00002787+ 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 +00002788% %
2789% %
2790% %
2791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2792%
cristy4c08aed2011-07-01 19:47:50 +00002793% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2794% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002795%
cristy4c08aed2011-07-01 19:47:50 +00002796% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002797%
cristy4c08aed2011-07-01 19:47:50 +00002798% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002799% NexusInfo *nexus_info)
2800%
2801% A description of each parameter follows:
2802%
2803% o cache: the pixel cache.
2804%
cristy4c08aed2011-07-01 19:47:50 +00002805% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002806%
2807*/
cristya6577ff2011-09-02 19:54:26 +00002808MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002809 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002810{
2811 CacheInfo
2812 *cache_info;
2813
cristye7cc7cf2010-09-21 13:26:47 +00002814 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002815 cache_info=(CacheInfo *) cache;
2816 assert(cache_info->signature == MagickSignature);
2817 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002818 return((void *) NULL);
2819 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002820}
2821
2822/*
2823%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2824% %
2825% %
2826% %
cristy4c08aed2011-07-01 19:47:50 +00002827% 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 +00002828% %
2829% %
2830% %
2831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2832%
cristy4c08aed2011-07-01 19:47:50 +00002833% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2834% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2835% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002836%
cristy4c08aed2011-07-01 19:47:50 +00002837% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002838%
cristy4c08aed2011-07-01 19:47:50 +00002839% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002840%
2841% A description of each parameter follows:
2842%
2843% o image: the image.
2844%
2845*/
cristy4c08aed2011-07-01 19:47:50 +00002846MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002847{
2848 CacheInfo
2849 *cache_info;
2850
cristy2036f5c2010-09-19 21:18:17 +00002851 const int
2852 id = GetOpenMPThreadId();
2853
cristy4c08aed2011-07-01 19:47:50 +00002854 const void
2855 *metacontent;
2856
cristy3ed852e2009-09-05 21:47:34 +00002857 assert(image != (const Image *) NULL);
2858 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002859 assert(image->cache != (Cache) NULL);
2860 cache_info=(CacheInfo *) image->cache;
2861 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002862 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2863 (GetVirtualMetacontentFromHandler) NULL)
2864 {
cristy9d07ce82012-02-14 13:58:05 +00002865 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(
2866 image);
cristy4c08aed2011-07-01 19:47:50 +00002867 return(metacontent);
2868 }
cristy2036f5c2010-09-19 21:18:17 +00002869 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002870 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2871 cache_info->nexus_info[id]);
2872 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002873}
2874
2875/*
2876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2877% %
2878% %
2879% %
2880+ 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 %
2881% %
2882% %
2883% %
2884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885%
2886% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2887% pixel cache as defined by the geometry parameters. A pointer to the pixels
2888% is returned if the pixels are transferred, otherwise a NULL is returned.
2889%
2890% The format of the GetVirtualPixelsFromNexus() method is:
2891%
cristy4c08aed2011-07-01 19:47:50 +00002892% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002893% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002894% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2895% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002896%
2897% A description of each parameter follows:
2898%
2899% o image: the image.
2900%
2901% o virtual_pixel_method: the virtual pixel method.
2902%
2903% o x,y,columns,rows: These values define the perimeter of a region of
2904% pixels.
2905%
2906% o nexus_info: the cache nexus to acquire.
2907%
2908% o exception: return any errors or warnings in this structure.
2909%
2910*/
2911
cristybb503372010-05-27 20:51:26 +00002912static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002913 DitherMatrix[64] =
2914 {
2915 0, 48, 12, 60, 3, 51, 15, 63,
2916 32, 16, 44, 28, 35, 19, 47, 31,
2917 8, 56, 4, 52, 11, 59, 7, 55,
2918 40, 24, 36, 20, 43, 27, 39, 23,
2919 2, 50, 14, 62, 1, 49, 13, 61,
2920 34, 18, 46, 30, 33, 17, 45, 29,
2921 10, 58, 6, 54, 9, 57, 5, 53,
2922 42, 26, 38, 22, 41, 25, 37, 21
2923 };
2924
cristybb503372010-05-27 20:51:26 +00002925static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002926{
cristybb503372010-05-27 20:51:26 +00002927 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002928 index;
2929
2930 index=x+DitherMatrix[x & 0x07]-32L;
2931 if (index < 0L)
2932 return(0L);
cristybb503372010-05-27 20:51:26 +00002933 if (index >= (ssize_t) columns)
2934 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002935 return(index);
2936}
2937
cristybb503372010-05-27 20:51:26 +00002938static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002939{
cristybb503372010-05-27 20:51:26 +00002940 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002941 index;
2942
2943 index=y+DitherMatrix[y & 0x07]-32L;
2944 if (index < 0L)
2945 return(0L);
cristybb503372010-05-27 20:51:26 +00002946 if (index >= (ssize_t) rows)
2947 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002948 return(index);
2949}
2950
cristybb503372010-05-27 20:51:26 +00002951static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002952{
2953 if (x < 0L)
2954 return(0L);
cristybb503372010-05-27 20:51:26 +00002955 if (x >= (ssize_t) columns)
2956 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002957 return(x);
2958}
2959
cristybb503372010-05-27 20:51:26 +00002960static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002961{
2962 if (y < 0L)
2963 return(0L);
cristybb503372010-05-27 20:51:26 +00002964 if (y >= (ssize_t) rows)
2965 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002966 return(y);
2967}
2968
cristybb503372010-05-27 20:51:26 +00002969static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002970{
cristybb503372010-05-27 20:51:26 +00002971 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002972}
2973
cristybb503372010-05-27 20:51:26 +00002974static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002975{
cristybb503372010-05-27 20:51:26 +00002976 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002977}
2978
cristybb503372010-05-27 20:51:26 +00002979static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2980 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002981{
2982 MagickModulo
2983 modulo;
2984
cristy6162bb42011-07-18 11:34:09 +00002985 /*
2986 Compute the remainder of dividing offset by extent. It returns not only
2987 the quotient (tile the offset falls in) but also the positive remainer
2988 within that tile such that 0 <= remainder < extent. This method is
2989 essentially a ldiv() using a floored modulo division rather than the
2990 normal default truncated modulo division.
2991 */
cristybb503372010-05-27 20:51:26 +00002992 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002993 if (offset < 0L)
2994 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00002995 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002996 return(modulo);
2997}
2998
cristya6577ff2011-09-02 19:54:26 +00002999MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003000 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3001 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003002 ExceptionInfo *exception)
3003{
3004 CacheInfo
3005 *cache_info;
3006
3007 MagickOffsetType
3008 offset;
3009
3010 MagickSizeType
3011 length,
3012 number_pixels;
3013
3014 NexusInfo
3015 **virtual_nexus;
3016
cristy4c08aed2011-07-01 19:47:50 +00003017 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003018 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003019 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003020
3021 RectangleInfo
3022 region;
3023
cristy4c08aed2011-07-01 19:47:50 +00003024 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003025 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003026
cristy4c08aed2011-07-01 19:47:50 +00003027 register const void
3028 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003029
cristy4c08aed2011-07-01 19:47:50 +00003030 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003031 *restrict q;
3032
cristybb503372010-05-27 20:51:26 +00003033 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003034 i,
3035 u;
cristy3ed852e2009-09-05 21:47:34 +00003036
cristy4c08aed2011-07-01 19:47:50 +00003037 register unsigned char
3038 *restrict s;
3039
cristy105ba3c2011-07-18 02:28:38 +00003040 ssize_t
3041 v;
3042
cristy4c08aed2011-07-01 19:47:50 +00003043 void
cristy105ba3c2011-07-18 02:28:38 +00003044 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003045
cristy3ed852e2009-09-05 21:47:34 +00003046 /*
3047 Acquire pixels.
3048 */
cristye7cc7cf2010-09-21 13:26:47 +00003049 assert(image != (const Image *) NULL);
3050 assert(image->signature == MagickSignature);
3051 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003052 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003053 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003054 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003055 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003056 region.x=x;
3057 region.y=y;
3058 region.width=columns;
3059 region.height=rows;
3060 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003061 if (pixels == (Quantum *) NULL)
3062 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003063 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003064 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3065 nexus_info->region.x;
3066 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3067 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003068 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3069 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003070 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3071 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003072 {
3073 MagickBooleanType
3074 status;
3075
3076 /*
3077 Pixel request is inside cache extents.
3078 */
cristy4c08aed2011-07-01 19:47:50 +00003079 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003080 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003081 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3082 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003083 return((const Quantum *) NULL);
3084 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003085 {
cristy4c08aed2011-07-01 19:47:50 +00003086 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003087 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003088 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003089 }
cristyacd2ed22011-08-30 01:44:23 +00003090 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003091 }
3092 /*
3093 Pixel request is outside cache extents.
3094 */
cristy4c08aed2011-07-01 19:47:50 +00003095 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003096 virtual_nexus=AcquirePixelCacheNexus(1);
3097 if (virtual_nexus == (NexusInfo **) NULL)
3098 {
cristy4c08aed2011-07-01 19:47:50 +00003099 if (virtual_nexus != (NexusInfo **) NULL)
3100 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003101 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3102 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003103 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003104 }
cristy105ba3c2011-07-18 02:28:38 +00003105 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3106 sizeof(*virtual_pixel));
3107 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003108 switch (virtual_pixel_method)
3109 {
cristy4c08aed2011-07-01 19:47:50 +00003110 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003111 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003112 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003113 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003114 case MaskVirtualPixelMethod:
3115 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003116 case EdgeVirtualPixelMethod:
3117 case CheckerTileVirtualPixelMethod:
3118 case HorizontalTileVirtualPixelMethod:
3119 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 {
cristy4c08aed2011-07-01 19:47:50 +00003121 if (cache_info->metacontent_extent != 0)
3122 {
cristy6162bb42011-07-18 11:34:09 +00003123 /*
3124 Acquire a metacontent buffer.
3125 */
cristya64b85d2011-09-14 01:02:31 +00003126 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003127 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003128 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003129 {
cristy4c08aed2011-07-01 19:47:50 +00003130 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3131 (void) ThrowMagickException(exception,GetMagickModule(),
3132 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3133 return((const Quantum *) NULL);
3134 }
cristy105ba3c2011-07-18 02:28:38 +00003135 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003136 cache_info->metacontent_extent);
3137 }
3138 switch (virtual_pixel_method)
3139 {
3140 case BlackVirtualPixelMethod:
3141 {
cristy30301712011-07-18 15:06:51 +00003142 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3143 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003144 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3145 break;
3146 }
3147 case GrayVirtualPixelMethod:
3148 {
cristy30301712011-07-18 15:06:51 +00003149 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003150 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3151 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003152 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3153 break;
3154 }
3155 case TransparentVirtualPixelMethod:
3156 {
cristy30301712011-07-18 15:06:51 +00003157 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3158 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003159 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3160 break;
3161 }
3162 case MaskVirtualPixelMethod:
3163 case WhiteVirtualPixelMethod:
3164 {
cristy30301712011-07-18 15:06:51 +00003165 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3166 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003167 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3168 break;
3169 }
3170 default:
3171 {
cristy9e0719b2011-12-29 03:45:45 +00003172 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3173 virtual_pixel);
3174 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3175 virtual_pixel);
3176 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3177 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003178 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3179 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003180 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3181 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003182 break;
3183 }
3184 }
cristy3ed852e2009-09-05 21:47:34 +00003185 break;
3186 }
3187 default:
cristy3ed852e2009-09-05 21:47:34 +00003188 break;
cristy3ed852e2009-09-05 21:47:34 +00003189 }
cristybb503372010-05-27 20:51:26 +00003190 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003191 {
cristybb503372010-05-27 20:51:26 +00003192 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003193 {
3194 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003195 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003196 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3197 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003198 {
3199 MagickModulo
3200 x_modulo,
3201 y_modulo;
3202
3203 /*
3204 Transfer a single pixel.
3205 */
3206 length=(MagickSizeType) 1;
3207 switch (virtual_pixel_method)
3208 {
cristy3ed852e2009-09-05 21:47:34 +00003209 default:
3210 {
3211 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003212 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003213 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003214 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003215 break;
3216 }
3217 case RandomVirtualPixelMethod:
3218 {
3219 if (cache_info->random_info == (RandomInfo *) NULL)
3220 cache_info->random_info=AcquireRandomInfo();
3221 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003222 RandomX(cache_info->random_info,cache_info->columns),
3223 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003224 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003225 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003226 break;
3227 }
3228 case DitherVirtualPixelMethod:
3229 {
3230 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003231 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003232 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003233 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003234 break;
3235 }
3236 case TileVirtualPixelMethod:
3237 {
3238 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3239 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3240 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003241 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003242 exception);
cristy4c08aed2011-07-01 19:47:50 +00003243 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003244 break;
3245 }
3246 case MirrorVirtualPixelMethod:
3247 {
3248 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3249 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003250 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003251 x_modulo.remainder-1L;
3252 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3253 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003254 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003255 y_modulo.remainder-1L;
3256 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003257 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003258 exception);
cristy4c08aed2011-07-01 19:47:50 +00003259 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003260 break;
3261 }
3262 case HorizontalTileEdgeVirtualPixelMethod:
3263 {
3264 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3265 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003266 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003267 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003268 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003269 break;
3270 }
3271 case VerticalTileEdgeVirtualPixelMethod:
3272 {
3273 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3274 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003275 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003276 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003277 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3278 break;
3279 }
3280 case BackgroundVirtualPixelMethod:
3281 case BlackVirtualPixelMethod:
3282 case GrayVirtualPixelMethod:
3283 case TransparentVirtualPixelMethod:
3284 case MaskVirtualPixelMethod:
3285 case WhiteVirtualPixelMethod:
3286 {
3287 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003288 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003289 break;
3290 }
3291 case EdgeVirtualPixelMethod:
3292 case CheckerTileVirtualPixelMethod:
3293 {
3294 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3295 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3296 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3297 {
3298 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003299 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003300 break;
3301 }
3302 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3303 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3304 exception);
3305 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3306 break;
3307 }
3308 case HorizontalTileVirtualPixelMethod:
3309 {
3310 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3311 {
3312 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003313 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003314 break;
3315 }
3316 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3317 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3318 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3319 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3320 exception);
3321 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3322 break;
3323 }
3324 case VerticalTileVirtualPixelMethod:
3325 {
3326 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3327 {
3328 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003329 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003330 break;
3331 }
3332 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3333 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3335 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3336 exception);
3337 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003338 break;
3339 }
3340 }
cristy4c08aed2011-07-01 19:47:50 +00003341 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003342 break;
cristyed231572011-07-14 02:18:59 +00003343 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003344 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003345 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003346 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003347 {
3348 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3349 s+=cache_info->metacontent_extent;
3350 }
cristy3ed852e2009-09-05 21:47:34 +00003351 continue;
3352 }
3353 /*
3354 Transfer a run of pixels.
3355 */
cristy4c08aed2011-07-01 19:47:50 +00003356 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3357 length,1UL,*virtual_nexus,exception);
3358 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003359 break;
cristy4c08aed2011-07-01 19:47:50 +00003360 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003361 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3362 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003363 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003364 {
cristy4c08aed2011-07-01 19:47:50 +00003365 (void) memcpy(s,r,(size_t) length);
3366 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003367 }
3368 }
3369 }
cristy4c08aed2011-07-01 19:47:50 +00003370 /*
3371 Free resources.
3372 */
cristy105ba3c2011-07-18 02:28:38 +00003373 if (virtual_metacontent != (void *) NULL)
3374 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003375 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3376 return(pixels);
3377}
3378
3379/*
3380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3381% %
3382% %
3383% %
3384+ G e t V i r t u a l P i x e l C a c h e %
3385% %
3386% %
3387% %
3388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3389%
3390% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3391% cache as defined by the geometry parameters. A pointer to the pixels
3392% is returned if the pixels are transferred, otherwise a NULL is returned.
3393%
3394% The format of the GetVirtualPixelCache() method is:
3395%
cristy4c08aed2011-07-01 19:47:50 +00003396% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003397% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3398% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003399% ExceptionInfo *exception)
3400%
3401% A description of each parameter follows:
3402%
3403% o image: the image.
3404%
3405% o virtual_pixel_method: the virtual pixel method.
3406%
3407% o x,y,columns,rows: These values define the perimeter of a region of
3408% pixels.
3409%
3410% o exception: return any errors or warnings in this structure.
3411%
3412*/
cristy4c08aed2011-07-01 19:47:50 +00003413static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003414 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3415 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003416{
3417 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003418 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003419
cristy5c9e6f22010-09-17 17:31:01 +00003420 const int
3421 id = GetOpenMPThreadId();
3422
cristy4c08aed2011-07-01 19:47:50 +00003423 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003424 *p;
cristy4c08aed2011-07-01 19:47:50 +00003425
cristye7cc7cf2010-09-21 13:26:47 +00003426 assert(image != (const Image *) NULL);
3427 assert(image->signature == MagickSignature);
3428 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003429 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003430 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003431 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003432 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003433 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003434 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003435}
3436
3437/*
3438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3439% %
3440% %
3441% %
3442% G e t V i r t u a l P i x e l Q u e u e %
3443% %
3444% %
3445% %
3446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3447%
cristy4c08aed2011-07-01 19:47:50 +00003448% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3449% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003450%
3451% The format of the GetVirtualPixelQueue() method is:
3452%
cristy4c08aed2011-07-01 19:47:50 +00003453% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003454%
3455% A description of each parameter follows:
3456%
3457% o image: the image.
3458%
3459*/
cristy4c08aed2011-07-01 19:47:50 +00003460MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003461{
3462 CacheInfo
3463 *cache_info;
3464
cristy2036f5c2010-09-19 21:18:17 +00003465 const int
3466 id = GetOpenMPThreadId();
3467
cristy3ed852e2009-09-05 21:47:34 +00003468 assert(image != (const Image *) NULL);
3469 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003470 assert(image->cache != (Cache) NULL);
3471 cache_info=(CacheInfo *) image->cache;
3472 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003473 if (cache_info->methods.get_virtual_pixels_handler !=
3474 (GetVirtualPixelsHandler) NULL)
3475 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003476 assert(id < (int) cache_info->number_threads);
3477 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003478}
3479
3480/*
3481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3482% %
3483% %
3484% %
3485% G e t V i r t u a l P i x e l s %
3486% %
3487% %
3488% %
3489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3490%
3491% GetVirtualPixels() returns an immutable pixel region. If the
3492% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003493% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003494% copy of the pixels or it may point to the original pixels in memory.
3495% Performance is maximized if the selected region is part of one row, or one
3496% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003497% (without a copy) if the image is in memory, or in a memory-mapped file. The
3498% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003499%
3500% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003501% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3502% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3503% access the meta-content (of type void) corresponding to the the
3504% region.
cristy3ed852e2009-09-05 21:47:34 +00003505%
3506% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3507%
3508% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3509% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3510% GetCacheViewAuthenticPixels() instead.
3511%
3512% The format of the GetVirtualPixels() method is:
3513%
cristy4c08aed2011-07-01 19:47:50 +00003514% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003515% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003516% ExceptionInfo *exception)
3517%
3518% A description of each parameter follows:
3519%
3520% o image: the image.
3521%
3522% o x,y,columns,rows: These values define the perimeter of a region of
3523% pixels.
3524%
3525% o exception: return any errors or warnings in this structure.
3526%
3527*/
cristy4c08aed2011-07-01 19:47:50 +00003528MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003529 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3530 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003531{
3532 CacheInfo
3533 *cache_info;
3534
cristy2036f5c2010-09-19 21:18:17 +00003535 const int
3536 id = GetOpenMPThreadId();
3537
cristy4c08aed2011-07-01 19:47:50 +00003538 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003539 *p;
cristy4c08aed2011-07-01 19:47:50 +00003540
cristy3ed852e2009-09-05 21:47:34 +00003541 assert(image != (const Image *) NULL);
3542 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003543 assert(image->cache != (Cache) NULL);
3544 cache_info=(CacheInfo *) image->cache;
3545 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003546 if (cache_info->methods.get_virtual_pixel_handler !=
3547 (GetVirtualPixelHandler) NULL)
3548 return(cache_info->methods.get_virtual_pixel_handler(image,
3549 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003550 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003551 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003552 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003553 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003554}
3555
3556/*
3557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3558% %
3559% %
3560% %
3561+ 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 %
3562% %
3563% %
3564% %
3565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3566%
cristy4c08aed2011-07-01 19:47:50 +00003567% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3568% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003569%
3570% The format of the GetVirtualPixelsCache() method is:
3571%
cristy4c08aed2011-07-01 19:47:50 +00003572% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003573%
3574% A description of each parameter follows:
3575%
3576% o image: the image.
3577%
3578*/
cristy4c08aed2011-07-01 19:47:50 +00003579static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003580{
3581 CacheInfo
3582 *cache_info;
3583
cristy5c9e6f22010-09-17 17:31:01 +00003584 const int
3585 id = GetOpenMPThreadId();
3586
cristye7cc7cf2010-09-21 13:26:47 +00003587 assert(image != (const Image *) NULL);
3588 assert(image->signature == MagickSignature);
3589 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003590 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003591 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003592 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003593 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003594}
3595
3596/*
3597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3598% %
3599% %
3600% %
3601+ G e t V i r t u a l P i x e l s N e x u s %
3602% %
3603% %
3604% %
3605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3606%
3607% GetVirtualPixelsNexus() returns the pixels associated with the specified
3608% cache nexus.
3609%
3610% The format of the GetVirtualPixelsNexus() method is:
3611%
cristy4c08aed2011-07-01 19:47:50 +00003612% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003613% NexusInfo *nexus_info)
3614%
3615% A description of each parameter follows:
3616%
3617% o cache: the pixel cache.
3618%
3619% o nexus_info: the cache nexus to return the colormap pixels.
3620%
3621*/
cristya6577ff2011-09-02 19:54:26 +00003622MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003623 NexusInfo *nexus_info)
3624{
3625 CacheInfo
3626 *cache_info;
3627
cristye7cc7cf2010-09-21 13:26:47 +00003628 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003629 cache_info=(CacheInfo *) cache;
3630 assert(cache_info->signature == MagickSignature);
3631 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003632 return((Quantum *) NULL);
3633 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003634}
3635
3636/*
3637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3638% %
3639% %
3640% %
cristy3ed852e2009-09-05 21:47:34 +00003641+ O p e n P i x e l C a c h e %
3642% %
3643% %
3644% %
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646%
3647% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3648% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003649% metacontent, and memory mapping the cache if it is disk based. The cache
3650% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003651%
3652% The format of the OpenPixelCache() method is:
3653%
3654% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3655% ExceptionInfo *exception)
3656%
3657% A description of each parameter follows:
3658%
3659% o image: the image.
3660%
3661% o mode: ReadMode, WriteMode, or IOMode.
3662%
3663% o exception: return any errors or warnings in this structure.
3664%
3665*/
3666
cristyd43a46b2010-01-21 02:13:41 +00003667static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003668{
3669 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003670 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003671 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003672 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003673 {
3674 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003675 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003676 cache_info->length);
3677 }
3678}
3679
3680static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3681{
3682 CacheInfo
3683 *cache_info;
3684
3685 MagickOffsetType
3686 count,
3687 extent,
3688 offset;
3689
3690 cache_info=(CacheInfo *) image->cache;
3691 if (image->debug != MagickFalse)
3692 {
3693 char
3694 format[MaxTextExtent],
3695 message[MaxTextExtent];
3696
cristyb9080c92009-12-01 20:13:26 +00003697 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003698 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003699 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003700 cache_info->cache_filename,cache_info->file,format);
3701 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3702 }
3703 if (length != (MagickSizeType) ((MagickOffsetType) length))
3704 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003705 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003706 if (extent < 0)
3707 return(MagickFalse);
3708 if ((MagickSizeType) extent >= length)
3709 return(MagickTrue);
3710 offset=(MagickOffsetType) length-1;
3711 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3712 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3713}
3714
3715static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3716 ExceptionInfo *exception)
3717{
cristy3ed852e2009-09-05 21:47:34 +00003718 CacheInfo
3719 *cache_info,
3720 source_info;
3721
cristyf3a6a9d2010-11-07 21:02:56 +00003722 char
3723 format[MaxTextExtent],
3724 message[MaxTextExtent];
3725
cristy4c08aed2011-07-01 19:47:50 +00003726 MagickBooleanType
3727 status;
3728
cristy3ed852e2009-09-05 21:47:34 +00003729 MagickSizeType
3730 length,
3731 number_pixels;
3732
cristy3b8fe922011-12-29 18:56:23 +00003733 PixelChannelMap
3734 *p,
3735 *q;
3736
cristy3ed852e2009-09-05 21:47:34 +00003737 size_t
cristye076a6e2010-08-15 19:59:43 +00003738 columns,
cristy3ed852e2009-09-05 21:47:34 +00003739 packet_size;
3740
cristye7cc7cf2010-09-21 13:26:47 +00003741 assert(image != (const Image *) NULL);
3742 assert(image->signature == MagickSignature);
3743 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003744 if (image->debug != MagickFalse)
3745 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3746 if ((image->columns == 0) || (image->rows == 0))
3747 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3748 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003749 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003750 source_info=(*cache_info);
3751 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003752 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003753 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003754 cache_info->storage_class=image->storage_class;
3755 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003756 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003757 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003758 cache_info->rows=image->rows;
3759 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003760 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003761 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003762 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3763 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003764 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003765 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003766 if (image->ping != MagickFalse)
3767 {
cristy73724512010-04-12 14:43:14 +00003768 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003769 cache_info->pixels=(Quantum *) NULL;
3770 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003771 cache_info->length=0;
3772 return(MagickTrue);
3773 }
cristy3ed852e2009-09-05 21:47:34 +00003774 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003775 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003776 if (image->metacontent_extent != 0)
3777 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003778 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003779 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003780 if (cache_info->columns != columns)
3781 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3782 image->filename);
3783 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00003784 p=cache_info->channel_map;
3785 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00003786 if ((cache_info->type != UndefinedCache) &&
3787 (cache_info->columns <= source_info.columns) &&
3788 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00003789 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00003790 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00003791 (cache_info->metacontent_extent <= source_info.metacontent_extent))
3792 {
3793 /*
3794 Inline pixel cache clone optimization.
3795 */
3796 if ((cache_info->columns == source_info.columns) &&
3797 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00003798 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00003799 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00003800 (cache_info->metacontent_extent == source_info.metacontent_extent))
3801 return(MagickTrue);
3802 return(ClonePixelCachePixels(cache_info,&source_info,exception));
3803 }
cristy3ed852e2009-09-05 21:47:34 +00003804 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003805 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003806 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003807 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3808 {
3809 status=AcquireMagickResource(MemoryResource,cache_info->length);
3810 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3811 (cache_info->type == MemoryCache))
3812 {
cristyd43a46b2010-01-21 02:13:41 +00003813 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003814 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003815 cache_info->pixels=source_info.pixels;
3816 else
3817 {
3818 /*
3819 Create memory pixel cache.
3820 */
cristy4c08aed2011-07-01 19:47:50 +00003821 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003822 if (image->debug != MagickFalse)
3823 {
cristy32cacff2011-12-31 03:36:27 +00003824 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003825 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003826 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3827 cache_info->filename,cache_info->mapped != MagickFalse ?
3828 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003829 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003830 format);
cristy3ed852e2009-09-05 21:47:34 +00003831 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3832 message);
3833 }
cristy3ed852e2009-09-05 21:47:34 +00003834 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003835 cache_info->metacontent=(void *) NULL;
3836 if (cache_info->metacontent_extent != 0)
3837 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003838 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003839 if ((source_info.storage_class != UndefinedClass) &&
3840 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003841 {
cristy4c08aed2011-07-01 19:47:50 +00003842 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003843 exception);
3844 RelinquishPixelCachePixels(&source_info);
3845 }
cristy4c08aed2011-07-01 19:47:50 +00003846 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003847 }
3848 }
3849 RelinquishMagickResource(MemoryResource,cache_info->length);
3850 }
3851 /*
3852 Create pixel cache on disk.
3853 */
3854 status=AcquireMagickResource(DiskResource,cache_info->length);
3855 if (status == MagickFalse)
3856 {
3857 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3858 "CacheResourcesExhausted","`%s'",image->filename);
3859 return(MagickFalse);
3860 }
cristy413f1302012-01-01 17:48:27 +00003861 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3862 {
3863 (void) ClosePixelCacheOnDisk(cache_info);
3864 *cache_info->cache_filename='\0';
3865 }
cristy3ed852e2009-09-05 21:47:34 +00003866 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3867 {
3868 RelinquishMagickResource(DiskResource,cache_info->length);
3869 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3870 image->filename);
3871 return(MagickFalse);
3872 }
3873 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3874 cache_info->length);
3875 if (status == MagickFalse)
3876 {
3877 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3878 image->filename);
3879 return(MagickFalse);
3880 }
cristyed231572011-07-14 02:18:59 +00003881 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003882 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003883 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003884 cache_info->type=DiskCache;
3885 else
3886 {
3887 status=AcquireMagickResource(MapResource,cache_info->length);
3888 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3889 (cache_info->type != MemoryCache))
3890 cache_info->type=DiskCache;
3891 else
3892 {
cristy4c08aed2011-07-01 19:47:50 +00003893 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003894 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003895 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003896 {
cristy3ed852e2009-09-05 21:47:34 +00003897 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003898 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003899 }
3900 else
3901 {
3902 /*
3903 Create file-backed memory-mapped pixel cache.
3904 */
cristy4c08aed2011-07-01 19:47:50 +00003905 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003906 (void) ClosePixelCacheOnDisk(cache_info);
3907 cache_info->type=MapCache;
3908 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003909 cache_info->metacontent=(void *) NULL;
3910 if (cache_info->metacontent_extent != 0)
3911 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003912 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003913 if ((source_info.storage_class != UndefinedClass) &&
3914 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003915 {
3916 status=ClonePixelCachePixels(cache_info,&source_info,
3917 exception);
3918 RelinquishPixelCachePixels(&source_info);
3919 }
3920 if (image->debug != MagickFalse)
3921 {
cristy413f1302012-01-01 17:48:27 +00003922 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003923 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003924 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003925 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003926 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003927 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003928 format);
cristy3ed852e2009-09-05 21:47:34 +00003929 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3930 message);
3931 }
cristy4c08aed2011-07-01 19:47:50 +00003932 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003933 }
3934 }
3935 RelinquishMagickResource(MapResource,cache_info->length);
3936 }
cristy4c08aed2011-07-01 19:47:50 +00003937 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003938 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003939 {
3940 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3941 RelinquishPixelCachePixels(&source_info);
3942 }
3943 if (image->debug != MagickFalse)
3944 {
cristyb9080c92009-12-01 20:13:26 +00003945 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003946 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003947 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003948 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003949 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003950 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3952 }
cristy4c08aed2011-07-01 19:47:50 +00003953 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003954}
3955
3956/*
3957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3958% %
3959% %
3960% %
3961+ P e r s i s t P i x e l C a c h e %
3962% %
3963% %
3964% %
3965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3966%
3967% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3968% persistent pixel cache is one that resides on disk and is not destroyed
3969% when the program exits.
3970%
3971% The format of the PersistPixelCache() method is:
3972%
3973% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3974% const MagickBooleanType attach,MagickOffsetType *offset,
3975% ExceptionInfo *exception)
3976%
3977% A description of each parameter follows:
3978%
3979% o image: the image.
3980%
3981% o filename: the persistent pixel cache filename.
3982%
cristyf3a6a9d2010-11-07 21:02:56 +00003983% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003984%
cristy3ed852e2009-09-05 21:47:34 +00003985% o initialize: A value other than zero initializes the persistent pixel
3986% cache.
3987%
3988% o offset: the offset in the persistent cache to store pixels.
3989%
3990% o exception: return any errors or warnings in this structure.
3991%
3992*/
3993MagickExport MagickBooleanType PersistPixelCache(Image *image,
3994 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3995 ExceptionInfo *exception)
3996{
3997 CacheInfo
3998 *cache_info,
3999 *clone_info;
4000
4001 Image
4002 clone_image;
4003
cristy3ed852e2009-09-05 21:47:34 +00004004 MagickBooleanType
4005 status;
4006
cristye076a6e2010-08-15 19:59:43 +00004007 ssize_t
4008 page_size;
4009
cristy3ed852e2009-09-05 21:47:34 +00004010 assert(image != (Image *) NULL);
4011 assert(image->signature == MagickSignature);
4012 if (image->debug != MagickFalse)
4013 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4014 assert(image->cache != (void *) NULL);
4015 assert(filename != (const char *) NULL);
4016 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004017 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004018 cache_info=(CacheInfo *) image->cache;
4019 assert(cache_info->signature == MagickSignature);
4020 if (attach != MagickFalse)
4021 {
4022 /*
cristy01b7eb02009-09-10 23:10:14 +00004023 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004024 */
4025 if (image->debug != MagickFalse)
4026 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004027 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004028 (void) CopyMagickString(cache_info->cache_filename,filename,
4029 MaxTextExtent);
4030 cache_info->type=DiskCache;
4031 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004032 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004033 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004034 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004035 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004036 }
cristy01b7eb02009-09-10 23:10:14 +00004037 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4038 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004039 {
cristyf84a1932010-01-03 18:00:18 +00004040 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004041 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004042 (cache_info->reference_count == 1))
4043 {
4044 int
4045 status;
4046
4047 /*
cristy01b7eb02009-09-10 23:10:14 +00004048 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004049 */
cristy320684d2011-09-23 14:55:47 +00004050 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004051 if (status == 0)
4052 {
4053 (void) CopyMagickString(cache_info->cache_filename,filename,
4054 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004055 *offset+=cache_info->length+page_size-(cache_info->length %
4056 page_size);
cristyf84a1932010-01-03 18:00:18 +00004057 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004058 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004059 if (image->debug != MagickFalse)
4060 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4061 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004062 return(MagickTrue);
4063 }
4064 }
cristyf84a1932010-01-03 18:00:18 +00004065 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004066 }
4067 /*
cristy01b7eb02009-09-10 23:10:14 +00004068 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004069 */
4070 clone_image=(*image);
4071 clone_info=(CacheInfo *) clone_image.cache;
4072 image->cache=ClonePixelCache(cache_info);
4073 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4074 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4075 cache_info->type=DiskCache;
4076 cache_info->offset=(*offset);
4077 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004078 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004079 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004080 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004081 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004082 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4083 return(status);
4084}
4085
4086/*
4087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4088% %
4089% %
4090% %
cristyc11dace2012-01-24 16:39:46 +00004091+ 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 +00004092% %
4093% %
4094% %
4095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4096%
cristyc11dace2012-01-24 16:39:46 +00004097% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4098% defined by the region rectangle and returns a pointer to the region. This
4099% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004100% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4101% pixels are transferred, otherwise a NULL is returned.
4102%
cristyc11dace2012-01-24 16:39:46 +00004103% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004104%
cristyc11dace2012-01-24 16:39:46 +00004105% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004106% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004107% const MagickBooleanType clone,NexusInfo *nexus_info,
4108% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004109%
4110% A description of each parameter follows:
4111%
4112% o image: the image.
4113%
4114% o x,y,columns,rows: These values define the perimeter of a region of
4115% pixels.
4116%
4117% o nexus_info: the cache nexus to set.
4118%
cristy65dbf172011-10-06 17:32:04 +00004119% o clone: clone the pixel cache.
4120%
cristy3ed852e2009-09-05 21:47:34 +00004121% o exception: return any errors or warnings in this structure.
4122%
4123*/
cristyc11dace2012-01-24 16:39:46 +00004124MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4125 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004126 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004127{
4128 CacheInfo
4129 *cache_info;
4130
4131 MagickOffsetType
4132 offset;
4133
4134 MagickSizeType
4135 number_pixels;
4136
4137 RectangleInfo
4138 region;
4139
4140 /*
4141 Validate pixel cache geometry.
4142 */
cristye7cc7cf2010-09-21 13:26:47 +00004143 assert(image != (const Image *) NULL);
4144 assert(image->signature == MagickSignature);
4145 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004146 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004147 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004148 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004149 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004150 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4151 {
4152 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4153 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004154 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004155 }
cristybb503372010-05-27 20:51:26 +00004156 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4157 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004158 {
4159 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4160 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004161 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004162 }
4163 offset=(MagickOffsetType) y*cache_info->columns+x;
4164 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004165 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004166 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4167 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4168 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004169 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004170 /*
4171 Return pixel cache.
4172 */
4173 region.x=x;
4174 region.y=y;
4175 region.width=columns;
4176 region.height=rows;
4177 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4178}
4179
4180/*
4181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4182% %
4183% %
4184% %
4185+ 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 %
4186% %
4187% %
4188% %
4189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4190%
4191% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4192% defined by the region rectangle and returns a pointer to the region. This
4193% region is subsequently transferred from the pixel cache with
4194% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4195% pixels are transferred, otherwise a NULL is returned.
4196%
4197% The format of the QueueAuthenticPixelsCache() method is:
4198%
cristy4c08aed2011-07-01 19:47:50 +00004199% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004200% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004201% ExceptionInfo *exception)
4202%
4203% A description of each parameter follows:
4204%
4205% o image: the image.
4206%
4207% o x,y,columns,rows: These values define the perimeter of a region of
4208% pixels.
4209%
4210% o exception: return any errors or warnings in this structure.
4211%
4212*/
cristy4c08aed2011-07-01 19:47:50 +00004213static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004214 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004215 ExceptionInfo *exception)
4216{
4217 CacheInfo
4218 *cache_info;
4219
cristy5c9e6f22010-09-17 17:31:01 +00004220 const int
4221 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004222
cristy4c08aed2011-07-01 19:47:50 +00004223 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004224 *q;
cristy4c08aed2011-07-01 19:47:50 +00004225
cristye7cc7cf2010-09-21 13:26:47 +00004226 assert(image != (const Image *) NULL);
4227 assert(image->signature == MagickSignature);
4228 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004229 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004230 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004231 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004232 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004233 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004234 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004235}
4236
4237/*
4238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4239% %
4240% %
4241% %
4242% Q u e u e A u t h e n t i c P i x e l s %
4243% %
4244% %
4245% %
4246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4247%
4248% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004249% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004250% region is returned, otherwise NULL is returned. The returned pointer may
4251% point to a temporary working buffer for the pixels or it may point to the
4252% final location of the pixels in memory.
4253%
4254% Write-only access means that any existing pixel values corresponding to
4255% the region are ignored. This is useful if the initial image is being
4256% created from scratch, or if the existing pixel values are to be
4257% completely replaced without need to refer to their pre-existing values.
4258% The application is free to read and write the pixel buffer returned by
4259% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4260% initialize the pixel array values. Initializing pixel array values is the
4261% application's responsibility.
4262%
4263% Performance is maximized if the selected region is part of one row, or
4264% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004265% pixels in-place (without a copy) if the image is in memory, or in a
4266% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004267% by the user.
4268%
4269% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004270% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4271% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4272% obtain the meta-content (of type void) corresponding to the region.
4273% Once the Quantum (and/or Quantum) array has been updated, the
4274% changes must be saved back to the underlying image using
4275% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004276%
4277% The format of the QueueAuthenticPixels() method is:
4278%
cristy4c08aed2011-07-01 19:47:50 +00004279% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004280% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004281% ExceptionInfo *exception)
4282%
4283% A description of each parameter follows:
4284%
4285% o image: the image.
4286%
4287% o x,y,columns,rows: These values define the perimeter of a region of
4288% pixels.
4289%
4290% o exception: return any errors or warnings in this structure.
4291%
4292*/
cristy4c08aed2011-07-01 19:47:50 +00004293MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004294 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004295 ExceptionInfo *exception)
4296{
4297 CacheInfo
4298 *cache_info;
4299
cristy2036f5c2010-09-19 21:18:17 +00004300 const int
4301 id = GetOpenMPThreadId();
4302
cristy4c08aed2011-07-01 19:47:50 +00004303 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004304 *q;
cristy4c08aed2011-07-01 19:47:50 +00004305
cristy3ed852e2009-09-05 21:47:34 +00004306 assert(image != (Image *) NULL);
4307 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004308 assert(image->cache != (Cache) NULL);
4309 cache_info=(CacheInfo *) image->cache;
4310 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004311 if (cache_info->methods.queue_authentic_pixels_handler !=
4312 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004313 {
cristyacd2ed22011-08-30 01:44:23 +00004314 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004315 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004316 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004317 }
cristy2036f5c2010-09-19 21:18:17 +00004318 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004319 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004320 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004321 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004322}
4323
4324/*
4325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4326% %
4327% %
4328% %
cristy4c08aed2011-07-01 19:47:50 +00004329+ 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 +00004330% %
4331% %
4332% %
4333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4334%
cristy4c08aed2011-07-01 19:47:50 +00004335% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004336% the pixel cache.
4337%
cristy4c08aed2011-07-01 19:47:50 +00004338% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004339%
cristy4c08aed2011-07-01 19:47:50 +00004340% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004341% NexusInfo *nexus_info,ExceptionInfo *exception)
4342%
4343% A description of each parameter follows:
4344%
4345% o cache_info: the pixel cache.
4346%
cristy4c08aed2011-07-01 19:47:50 +00004347% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004348%
4349% o exception: return any errors or warnings in this structure.
4350%
4351*/
cristy4c08aed2011-07-01 19:47:50 +00004352static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004353 NexusInfo *nexus_info,ExceptionInfo *exception)
4354{
4355 MagickOffsetType
4356 count,
4357 offset;
4358
4359 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004360 extent,
4361 length;
cristy3ed852e2009-09-05 21:47:34 +00004362
cristybb503372010-05-27 20:51:26 +00004363 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004364 y;
4365
cristy4c08aed2011-07-01 19:47:50 +00004366 register unsigned char
4367 *restrict q;
4368
cristybb503372010-05-27 20:51:26 +00004369 size_t
cristy3ed852e2009-09-05 21:47:34 +00004370 rows;
4371
cristy4c08aed2011-07-01 19:47:50 +00004372 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004373 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004374 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004375 return(MagickTrue);
4376 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4377 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004378 length=(MagickSizeType) nexus_info->region.width*
4379 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004380 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004381 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004382 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004383 switch (cache_info->type)
4384 {
4385 case MemoryCache:
4386 case MapCache:
4387 {
cristy4c08aed2011-07-01 19:47:50 +00004388 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004389 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004390
4391 /*
cristy4c08aed2011-07-01 19:47:50 +00004392 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004393 */
cristydd341db2010-03-04 19:06:38 +00004394 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004395 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004396 {
cristy48078b12010-09-23 17:11:01 +00004397 length=extent;
cristydd341db2010-03-04 19:06:38 +00004398 rows=1UL;
4399 }
cristy4c08aed2011-07-01 19:47:50 +00004400 p=(unsigned char *) cache_info->metacontent+offset*
4401 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004402 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004403 {
cristy8f036fe2010-09-18 02:02:00 +00004404 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004405 p+=cache_info->metacontent_extent*cache_info->columns;
4406 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004407 }
4408 break;
4409 }
4410 case DiskCache:
4411 {
4412 /*
cristy4c08aed2011-07-01 19:47:50 +00004413 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004414 */
4415 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4416 {
4417 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4418 cache_info->cache_filename);
4419 return(MagickFalse);
4420 }
cristydd341db2010-03-04 19:06:38 +00004421 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004422 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004423 {
cristy48078b12010-09-23 17:11:01 +00004424 length=extent;
cristydd341db2010-03-04 19:06:38 +00004425 rows=1UL;
4426 }
cristy48078b12010-09-23 17:11:01 +00004427 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004428 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004429 {
cristy48078b12010-09-23 17:11:01 +00004430 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004431 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004432 cache_info->metacontent_extent,length,(unsigned char *) q);
4433 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004434 break;
4435 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004436 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004437 }
cristyc11dace2012-01-24 16:39:46 +00004438 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4439 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004440 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004441 {
4442 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4443 cache_info->cache_filename);
4444 return(MagickFalse);
4445 }
4446 break;
4447 }
4448 default:
4449 break;
4450 }
4451 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004452 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004453 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004454 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004455 nexus_info->region.width,(double) nexus_info->region.height,(double)
4456 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004457 return(MagickTrue);
4458}
4459
4460/*
4461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4462% %
4463% %
4464% %
4465+ R e a d P i x e l C a c h e P i x e l s %
4466% %
4467% %
4468% %
4469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4470%
4471% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4472% cache.
4473%
4474% The format of the ReadPixelCachePixels() method is:
4475%
4476% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4477% NexusInfo *nexus_info,ExceptionInfo *exception)
4478%
4479% A description of each parameter follows:
4480%
4481% o cache_info: the pixel cache.
4482%
4483% o nexus_info: the cache nexus to read the pixels.
4484%
4485% o exception: return any errors or warnings in this structure.
4486%
4487*/
4488static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4489 NexusInfo *nexus_info,ExceptionInfo *exception)
4490{
4491 MagickOffsetType
4492 count,
4493 offset;
4494
4495 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004496 extent,
4497 length;
cristy3ed852e2009-09-05 21:47:34 +00004498
cristy4c08aed2011-07-01 19:47:50 +00004499 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004500 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004501
cristye076a6e2010-08-15 19:59:43 +00004502 register ssize_t
4503 y;
4504
cristybb503372010-05-27 20:51:26 +00004505 size_t
cristy3ed852e2009-09-05 21:47:34 +00004506 rows;
4507
cristy4c08aed2011-07-01 19:47:50 +00004508 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004509 return(MagickTrue);
4510 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4511 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004512 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004513 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004514 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004515 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004516 q=nexus_info->pixels;
4517 switch (cache_info->type)
4518 {
4519 case MemoryCache:
4520 case MapCache:
4521 {
cristy4c08aed2011-07-01 19:47:50 +00004522 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004523 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004524
4525 /*
4526 Read pixels from memory.
4527 */
cristydd341db2010-03-04 19:06:38 +00004528 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004529 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004530 {
cristy48078b12010-09-23 17:11:01 +00004531 length=extent;
cristydd341db2010-03-04 19:06:38 +00004532 rows=1UL;
4533 }
cristyed231572011-07-14 02:18:59 +00004534 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004535 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004536 {
cristy8f036fe2010-09-18 02:02:00 +00004537 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004538 p+=cache_info->number_channels*cache_info->columns;
4539 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004540 }
4541 break;
4542 }
4543 case DiskCache:
4544 {
4545 /*
4546 Read pixels from disk.
4547 */
4548 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4549 {
4550 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4551 cache_info->cache_filename);
4552 return(MagickFalse);
4553 }
cristydd341db2010-03-04 19:06:38 +00004554 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004555 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004556 {
cristy48078b12010-09-23 17:11:01 +00004557 length=extent;
cristydd341db2010-03-04 19:06:38 +00004558 rows=1UL;
4559 }
cristybb503372010-05-27 20:51:26 +00004560 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004561 {
4562 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004563 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004564 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004565 break;
4566 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004567 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004568 }
cristyc11dace2012-01-24 16:39:46 +00004569 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4570 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004571 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004572 {
4573 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4574 cache_info->cache_filename);
4575 return(MagickFalse);
4576 }
4577 break;
4578 }
4579 default:
4580 break;
4581 }
4582 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004583 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004584 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004585 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004586 nexus_info->region.width,(double) nexus_info->region.height,(double)
4587 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004588 return(MagickTrue);
4589}
4590
4591/*
4592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4593% %
4594% %
4595% %
4596+ R e f e r e n c e P i x e l C a c h e %
4597% %
4598% %
4599% %
4600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4601%
4602% ReferencePixelCache() increments the reference count associated with the
4603% pixel cache returning a pointer to the cache.
4604%
4605% The format of the ReferencePixelCache method is:
4606%
4607% Cache ReferencePixelCache(Cache cache_info)
4608%
4609% A description of each parameter follows:
4610%
4611% o cache_info: the pixel cache.
4612%
4613*/
cristya6577ff2011-09-02 19:54:26 +00004614MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004615{
4616 CacheInfo
4617 *cache_info;
4618
4619 assert(cache != (Cache *) NULL);
4620 cache_info=(CacheInfo *) cache;
4621 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004622 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004623 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004624 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004625 return(cache_info);
4626}
4627
4628/*
4629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4630% %
4631% %
4632% %
4633+ S e t P i x e l C a c h e M e t h o d s %
4634% %
4635% %
4636% %
4637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4638%
4639% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4640%
4641% The format of the SetPixelCacheMethods() method is:
4642%
4643% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4644%
4645% A description of each parameter follows:
4646%
4647% o cache: the pixel cache.
4648%
4649% o cache_methods: Specifies a pointer to a CacheMethods structure.
4650%
4651*/
cristya6577ff2011-09-02 19:54:26 +00004652MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004653{
4654 CacheInfo
4655 *cache_info;
4656
4657 GetOneAuthenticPixelFromHandler
4658 get_one_authentic_pixel_from_handler;
4659
4660 GetOneVirtualPixelFromHandler
4661 get_one_virtual_pixel_from_handler;
4662
4663 /*
4664 Set cache pixel methods.
4665 */
4666 assert(cache != (Cache) NULL);
4667 assert(cache_methods != (CacheMethods *) NULL);
4668 cache_info=(CacheInfo *) cache;
4669 assert(cache_info->signature == MagickSignature);
4670 if (cache_info->debug != MagickFalse)
4671 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4672 cache_info->filename);
4673 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4674 cache_info->methods.get_virtual_pixel_handler=
4675 cache_methods->get_virtual_pixel_handler;
4676 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4677 cache_info->methods.destroy_pixel_handler=
4678 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004679 if (cache_methods->get_virtual_metacontent_from_handler !=
4680 (GetVirtualMetacontentFromHandler) NULL)
4681 cache_info->methods.get_virtual_metacontent_from_handler=
4682 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004683 if (cache_methods->get_authentic_pixels_handler !=
4684 (GetAuthenticPixelsHandler) NULL)
4685 cache_info->methods.get_authentic_pixels_handler=
4686 cache_methods->get_authentic_pixels_handler;
4687 if (cache_methods->queue_authentic_pixels_handler !=
4688 (QueueAuthenticPixelsHandler) NULL)
4689 cache_info->methods.queue_authentic_pixels_handler=
4690 cache_methods->queue_authentic_pixels_handler;
4691 if (cache_methods->sync_authentic_pixels_handler !=
4692 (SyncAuthenticPixelsHandler) NULL)
4693 cache_info->methods.sync_authentic_pixels_handler=
4694 cache_methods->sync_authentic_pixels_handler;
4695 if (cache_methods->get_authentic_pixels_from_handler !=
4696 (GetAuthenticPixelsFromHandler) NULL)
4697 cache_info->methods.get_authentic_pixels_from_handler=
4698 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004699 if (cache_methods->get_authentic_metacontent_from_handler !=
4700 (GetAuthenticMetacontentFromHandler) NULL)
4701 cache_info->methods.get_authentic_metacontent_from_handler=
4702 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004703 get_one_virtual_pixel_from_handler=
4704 cache_info->methods.get_one_virtual_pixel_from_handler;
4705 if (get_one_virtual_pixel_from_handler !=
4706 (GetOneVirtualPixelFromHandler) NULL)
4707 cache_info->methods.get_one_virtual_pixel_from_handler=
4708 cache_methods->get_one_virtual_pixel_from_handler;
4709 get_one_authentic_pixel_from_handler=
4710 cache_methods->get_one_authentic_pixel_from_handler;
4711 if (get_one_authentic_pixel_from_handler !=
4712 (GetOneAuthenticPixelFromHandler) NULL)
4713 cache_info->methods.get_one_authentic_pixel_from_handler=
4714 cache_methods->get_one_authentic_pixel_from_handler;
4715}
4716
4717/*
4718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4719% %
4720% %
4721% %
4722+ S e t P i x e l C a c h e N e x u s P i x e l s %
4723% %
4724% %
4725% %
4726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4727%
4728% SetPixelCacheNexusPixels() defines the region of the cache for the
4729% specified cache nexus.
4730%
4731% The format of the SetPixelCacheNexusPixels() method is:
4732%
cristy4c08aed2011-07-01 19:47:50 +00004733% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004734% const RectangleInfo *region,NexusInfo *nexus_info,
4735% ExceptionInfo *exception)
4736%
4737% A description of each parameter follows:
4738%
4739% o image: the image.
4740%
4741% o region: A pointer to the RectangleInfo structure that defines the
4742% region of this particular cache nexus.
4743%
4744% o nexus_info: the cache nexus to set.
4745%
4746% o exception: return any errors or warnings in this structure.
4747%
4748*/
cristyabd6e372010-09-15 19:11:26 +00004749
4750static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4751 NexusInfo *nexus_info,ExceptionInfo *exception)
4752{
4753 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4754 return(MagickFalse);
4755 nexus_info->mapped=MagickFalse;
cristy7dc8ac52012-01-10 20:14:52 +00004756 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004757 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004758 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004759 {
4760 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004761 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004762 nexus_info->length);
4763 }
cristy4c08aed2011-07-01 19:47:50 +00004764 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004765 {
4766 (void) ThrowMagickException(exception,GetMagickModule(),
4767 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4768 cache_info->filename);
4769 return(MagickFalse);
4770 }
4771 return(MagickTrue);
4772}
4773
cristy4c08aed2011-07-01 19:47:50 +00004774static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004775 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4776{
4777 CacheInfo
4778 *cache_info;
4779
4780 MagickBooleanType
4781 status;
4782
cristy3ed852e2009-09-05 21:47:34 +00004783 MagickSizeType
4784 length,
4785 number_pixels;
4786
cristy3ed852e2009-09-05 21:47:34 +00004787 cache_info=(CacheInfo *) image->cache;
4788 assert(cache_info->signature == MagickSignature);
4789 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004790 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004791 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004792 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004793 {
cristybb503372010-05-27 20:51:26 +00004794 ssize_t
cristybad067a2010-02-15 17:20:55 +00004795 x,
4796 y;
cristy3ed852e2009-09-05 21:47:34 +00004797
cristyeaedf062010-05-29 22:36:02 +00004798 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4799 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004800 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4801 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004802 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004803 ((nexus_info->region.width == cache_info->columns) ||
4804 ((nexus_info->region.width % cache_info->columns) == 0)))))
4805 {
4806 MagickOffsetType
4807 offset;
4808
4809 /*
4810 Pixels are accessed directly from memory.
4811 */
4812 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4813 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004814 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004815 offset;
4816 nexus_info->metacontent=(void *) NULL;
4817 if (cache_info->metacontent_extent != 0)
4818 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4819 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00004820 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004821 }
4822 }
4823 /*
4824 Pixels are stored in a cache region until they are synced to the cache.
4825 */
4826 number_pixels=(MagickSizeType) nexus_info->region.width*
4827 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004828 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004829 if (cache_info->metacontent_extent != 0)
4830 length+=number_pixels*cache_info->metacontent_extent;
4831 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004832 {
4833 nexus_info->length=length;
4834 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4835 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004836 {
4837 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004838 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004839 }
cristy3ed852e2009-09-05 21:47:34 +00004840 }
4841 else
4842 if (nexus_info->length != length)
4843 {
4844 RelinquishCacheNexusPixels(nexus_info);
4845 nexus_info->length=length;
4846 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4847 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004848 {
4849 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004850 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004851 }
cristy3ed852e2009-09-05 21:47:34 +00004852 }
4853 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004854 nexus_info->metacontent=(void *) NULL;
4855 if (cache_info->metacontent_extent != 0)
4856 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004857 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004858 return(nexus_info->pixels);
4859}
4860
4861/*
4862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4863% %
4864% %
4865% %
4866% 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 %
4867% %
4868% %
4869% %
4870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871%
4872% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4873% pixel cache and returns the previous setting. A virtual pixel is any pixel
4874% access that is outside the boundaries of the image cache.
4875%
4876% The format of the SetPixelCacheVirtualMethod() method is:
4877%
cristy387430f2012-02-07 13:09:46 +00004878% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4879% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004880%
4881% A description of each parameter follows:
4882%
4883% o image: the image.
4884%
4885% o virtual_pixel_method: choose the type of virtual pixel.
4886%
cristy387430f2012-02-07 13:09:46 +00004887% o exception: return any errors or warnings in this structure.
4888%
cristy3ed852e2009-09-05 21:47:34 +00004889*/
cristy3d4cb882012-02-07 19:11:26 +00004890
4891static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4892 ExceptionInfo *exception)
4893{
4894 CacheInfo
4895 *cache_info;
4896
4897 MagickBooleanType
4898 status;
4899
4900 ssize_t
4901 y;
4902
4903 assert(image != (Image *) NULL);
4904 assert(image->signature == MagickSignature);
4905 if (image->debug != MagickFalse)
4906 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4907 assert(image->cache != (Cache) NULL);
4908 cache_info=(CacheInfo *) image->cache;
4909 assert(cache_info->signature == MagickSignature);
4910 image->matte=MagickTrue;
4911 status=MagickTrue;
4912#if defined(MAGICKCORE_OPENMP_SUPPORT)
4913 #pragma omp parallel for schedule(static,4) shared(status)
4914#endif
4915 for (y=0; y < (ssize_t) image->rows; y++)
4916 {
4917 const int
4918 id = GetOpenMPThreadId();
4919
4920 register Quantum
4921 *restrict q;
4922
4923 register ssize_t
4924 x;
4925
4926 if (status == MagickFalse)
4927 continue;
4928 q=GetAuthenticPixelCacheNexus(image,0,y,image->columns,1,
4929 cache_info->nexus_info[id],exception);
4930 if (q == (Quantum *) NULL)
4931 {
4932 status=MagickFalse;
4933 continue;
4934 }
4935 for (x=0; x < (ssize_t) image->columns; x++)
4936 {
4937 SetPixelAlpha(image,alpha,q);
4938 q+=GetPixelChannels(image);
4939 }
4940 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4941 exception);
4942 }
4943 return(status);
4944}
4945
cristy387430f2012-02-07 13:09:46 +00004946MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4947 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004948{
4949 CacheInfo
4950 *cache_info;
4951
4952 VirtualPixelMethod
4953 method;
4954
4955 assert(image != (Image *) NULL);
4956 assert(image->signature == MagickSignature);
4957 if (image->debug != MagickFalse)
4958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4959 assert(image->cache != (Cache) NULL);
4960 cache_info=(CacheInfo *) image->cache;
4961 assert(cache_info->signature == MagickSignature);
4962 method=cache_info->virtual_pixel_method;
4963 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004964 switch (virtual_pixel_method)
4965 {
4966 case BackgroundVirtualPixelMethod:
4967 {
4968 if ((image->background_color.matte != MagickFalse) &&
4969 (image->matte == MagickFalse))
cristy3d4cb882012-02-07 19:11:26 +00004970 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004971 break;
4972 }
4973 case TransparentVirtualPixelMethod:
4974 {
4975 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00004976 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004977 break;
4978 }
4979 default:
4980 break;
4981 }
cristy3ed852e2009-09-05 21:47:34 +00004982 return(method);
4983}
4984
4985/*
4986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4987% %
4988% %
4989% %
4990+ 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 %
4991% %
4992% %
4993% %
4994%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4995%
4996% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4997% in-memory or disk cache. The method returns MagickTrue if the pixel region
4998% is synced, otherwise MagickFalse.
4999%
5000% The format of the SyncAuthenticPixelCacheNexus() method is:
5001%
5002% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5003% NexusInfo *nexus_info,ExceptionInfo *exception)
5004%
5005% A description of each parameter follows:
5006%
5007% o image: the image.
5008%
5009% o nexus_info: the cache nexus to sync.
5010%
5011% o exception: return any errors or warnings in this structure.
5012%
5013*/
cristya6577ff2011-09-02 19:54:26 +00005014MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005015 NexusInfo *nexus_info,ExceptionInfo *exception)
5016{
5017 CacheInfo
5018 *cache_info;
5019
5020 MagickBooleanType
5021 status;
5022
5023 /*
5024 Transfer pixels to the cache.
5025 */
5026 assert(image != (Image *) NULL);
5027 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005028 if (image->cache == (Cache) NULL)
5029 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5030 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005031 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005032 if (cache_info->type == UndefinedCache)
5033 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005034 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005035 return(MagickTrue);
5036 assert(cache_info->signature == MagickSignature);
5037 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005038 if ((cache_info->metacontent_extent != 0) &&
5039 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005040 return(MagickFalse);
5041 return(status);
5042}
5043
5044/*
5045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5046% %
5047% %
5048% %
5049+ S y n c A u t h e n t i c P i x e l C a c h e %
5050% %
5051% %
5052% %
5053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5054%
5055% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5056% or disk cache. The method returns MagickTrue if the pixel region is synced,
5057% otherwise MagickFalse.
5058%
5059% The format of the SyncAuthenticPixelsCache() method is:
5060%
5061% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5062% ExceptionInfo *exception)
5063%
5064% A description of each parameter follows:
5065%
5066% o image: the image.
5067%
5068% o exception: return any errors or warnings in this structure.
5069%
5070*/
5071static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5072 ExceptionInfo *exception)
5073{
5074 CacheInfo
5075 *cache_info;
5076
cristy5c9e6f22010-09-17 17:31:01 +00005077 const int
5078 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005079
cristy4c08aed2011-07-01 19:47:50 +00005080 MagickBooleanType
5081 status;
5082
cristye7cc7cf2010-09-21 13:26:47 +00005083 assert(image != (Image *) NULL);
5084 assert(image->signature == MagickSignature);
5085 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005086 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005087 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005088 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005089 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5090 exception);
5091 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005092}
5093
5094/*
5095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5096% %
5097% %
5098% %
5099% S y n c A u t h e n t i c P i x e l s %
5100% %
5101% %
5102% %
5103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5104%
5105% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5106% The method returns MagickTrue if the pixel region is flushed, otherwise
5107% MagickFalse.
5108%
5109% The format of the SyncAuthenticPixels() method is:
5110%
5111% MagickBooleanType SyncAuthenticPixels(Image *image,
5112% ExceptionInfo *exception)
5113%
5114% A description of each parameter follows:
5115%
5116% o image: the image.
5117%
5118% o exception: return any errors or warnings in this structure.
5119%
5120*/
5121MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5122 ExceptionInfo *exception)
5123{
5124 CacheInfo
5125 *cache_info;
5126
cristy2036f5c2010-09-19 21:18:17 +00005127 const int
5128 id = GetOpenMPThreadId();
5129
cristy4c08aed2011-07-01 19:47:50 +00005130 MagickBooleanType
5131 status;
5132
cristy3ed852e2009-09-05 21:47:34 +00005133 assert(image != (Image *) NULL);
5134 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005135 assert(image->cache != (Cache) NULL);
5136 cache_info=(CacheInfo *) image->cache;
5137 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005138 if (cache_info->methods.sync_authentic_pixels_handler !=
5139 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005140 {
5141 status=cache_info->methods.sync_authentic_pixels_handler(image,
5142 exception);
5143 return(status);
5144 }
cristy2036f5c2010-09-19 21:18:17 +00005145 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005146 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5147 exception);
5148 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005149}
5150
5151/*
5152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5153% %
5154% %
5155% %
cristyd1dd6e42011-09-04 01:46:08 +00005156+ 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 +00005157% %
5158% %
5159% %
5160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5161%
5162% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5163% The method returns MagickTrue if the pixel region is flushed, otherwise
5164% MagickFalse.
5165%
5166% The format of the SyncImagePixelCache() method is:
5167%
5168% MagickBooleanType SyncImagePixelCache(Image *image,
5169% ExceptionInfo *exception)
5170%
5171% A description of each parameter follows:
5172%
5173% o image: the image.
5174%
5175% o exception: return any errors or warnings in this structure.
5176%
5177*/
cristyd1dd6e42011-09-04 01:46:08 +00005178MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005179 ExceptionInfo *exception)
5180{
5181 CacheInfo
5182 *cache_info;
5183
5184 assert(image != (Image *) NULL);
5185 assert(exception != (ExceptionInfo *) NULL);
5186 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5187 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5188}
5189
5190/*
5191%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5192% %
5193% %
5194% %
cristy4c08aed2011-07-01 19:47:50 +00005195+ 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 +00005196% %
5197% %
5198% %
5199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5200%
cristy4c08aed2011-07-01 19:47:50 +00005201% WritePixelCacheMetacontent() writes the meta-content to the specified region
5202% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005203%
cristy4c08aed2011-07-01 19:47:50 +00005204% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005205%
cristy4c08aed2011-07-01 19:47:50 +00005206% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005207% NexusInfo *nexus_info,ExceptionInfo *exception)
5208%
5209% A description of each parameter follows:
5210%
5211% o cache_info: the pixel cache.
5212%
cristy4c08aed2011-07-01 19:47:50 +00005213% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005214%
5215% o exception: return any errors or warnings in this structure.
5216%
5217*/
cristy4c08aed2011-07-01 19:47:50 +00005218static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005219 NexusInfo *nexus_info,ExceptionInfo *exception)
5220{
5221 MagickOffsetType
5222 count,
5223 offset;
5224
5225 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005226 extent,
5227 length;
cristy3ed852e2009-09-05 21:47:34 +00005228
cristy4c08aed2011-07-01 19:47:50 +00005229 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005230 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005231
cristybb503372010-05-27 20:51:26 +00005232 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005233 y;
5234
cristybb503372010-05-27 20:51:26 +00005235 size_t
cristy3ed852e2009-09-05 21:47:34 +00005236 rows;
5237
cristy4c08aed2011-07-01 19:47:50 +00005238 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005239 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005240 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005241 return(MagickTrue);
5242 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5243 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005244 length=(MagickSizeType) nexus_info->region.width*
5245 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005246 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005247 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005248 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005249 switch (cache_info->type)
5250 {
5251 case MemoryCache:
5252 case MapCache:
5253 {
cristy4c08aed2011-07-01 19:47:50 +00005254 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005255 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005256
5257 /*
cristy4c08aed2011-07-01 19:47:50 +00005258 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005259 */
cristydd341db2010-03-04 19:06:38 +00005260 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005261 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005262 {
cristy48078b12010-09-23 17:11:01 +00005263 length=extent;
cristydd341db2010-03-04 19:06:38 +00005264 rows=1UL;
5265 }
cristy4c08aed2011-07-01 19:47:50 +00005266 q=(unsigned char *) cache_info->metacontent+offset*
5267 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005268 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005269 {
cristy8f036fe2010-09-18 02:02:00 +00005270 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005271 p+=nexus_info->region.width*cache_info->metacontent_extent;
5272 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005273 }
5274 break;
5275 }
5276 case DiskCache:
5277 {
5278 /*
cristy4c08aed2011-07-01 19:47:50 +00005279 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005280 */
5281 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5282 {
5283 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5284 cache_info->cache_filename);
5285 return(MagickFalse);
5286 }
cristydd341db2010-03-04 19:06:38 +00005287 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005288 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005289 {
cristy48078b12010-09-23 17:11:01 +00005290 length=extent;
cristydd341db2010-03-04 19:06:38 +00005291 rows=1UL;
5292 }
cristy48078b12010-09-23 17:11:01 +00005293 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005294 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005295 {
cristy48078b12010-09-23 17:11:01 +00005296 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005297 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005298 cache_info->metacontent_extent,length,(const unsigned char *) p);
5299 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005300 break;
cristy4c08aed2011-07-01 19:47:50 +00005301 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005302 offset+=cache_info->columns;
5303 }
cristyc11dace2012-01-24 16:39:46 +00005304 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5305 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005306 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005307 {
5308 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5309 cache_info->cache_filename);
5310 return(MagickFalse);
5311 }
5312 break;
5313 }
5314 default:
5315 break;
5316 }
5317 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005318 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005319 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005320 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005321 nexus_info->region.width,(double) nexus_info->region.height,(double)
5322 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005323 return(MagickTrue);
5324}
5325
5326/*
5327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5328% %
5329% %
5330% %
5331+ W r i t e C a c h e P i x e l s %
5332% %
5333% %
5334% %
5335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5336%
5337% WritePixelCachePixels() writes image pixels to the specified region of the
5338% pixel cache.
5339%
5340% The format of the WritePixelCachePixels() method is:
5341%
5342% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5343% NexusInfo *nexus_info,ExceptionInfo *exception)
5344%
5345% A description of each parameter follows:
5346%
5347% o cache_info: the pixel cache.
5348%
5349% o nexus_info: the cache nexus to write the pixels.
5350%
5351% o exception: return any errors or warnings in this structure.
5352%
5353*/
5354static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5355 NexusInfo *nexus_info,ExceptionInfo *exception)
5356{
5357 MagickOffsetType
5358 count,
5359 offset;
5360
5361 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005362 extent,
5363 length;
cristy3ed852e2009-09-05 21:47:34 +00005364
cristy4c08aed2011-07-01 19:47:50 +00005365 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005366 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005367
cristybb503372010-05-27 20:51:26 +00005368 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005369 y;
5370
cristybb503372010-05-27 20:51:26 +00005371 size_t
cristy3ed852e2009-09-05 21:47:34 +00005372 rows;
5373
cristy4c08aed2011-07-01 19:47:50 +00005374 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005375 return(MagickTrue);
5376 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5377 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005378 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005379 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005380 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005381 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005382 p=nexus_info->pixels;
5383 switch (cache_info->type)
5384 {
5385 case MemoryCache:
5386 case MapCache:
5387 {
cristy4c08aed2011-07-01 19:47:50 +00005388 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005389 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005390
5391 /*
5392 Write pixels to memory.
5393 */
cristydd341db2010-03-04 19:06:38 +00005394 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005395 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005396 {
cristy48078b12010-09-23 17:11:01 +00005397 length=extent;
cristydd341db2010-03-04 19:06:38 +00005398 rows=1UL;
5399 }
cristyed231572011-07-14 02:18:59 +00005400 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005401 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005402 {
cristy8f036fe2010-09-18 02:02:00 +00005403 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005404 p+=nexus_info->region.width*cache_info->number_channels;
5405 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005406 }
5407 break;
5408 }
5409 case DiskCache:
5410 {
5411 /*
5412 Write pixels to disk.
5413 */
5414 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5415 {
5416 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5417 cache_info->cache_filename);
5418 return(MagickFalse);
5419 }
cristydd341db2010-03-04 19:06:38 +00005420 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005421 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005422 {
cristy48078b12010-09-23 17:11:01 +00005423 length=extent;
cristydd341db2010-03-04 19:06:38 +00005424 rows=1UL;
5425 }
cristybb503372010-05-27 20:51:26 +00005426 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005427 {
5428 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005429 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005430 p);
5431 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005432 break;
cristyed231572011-07-14 02:18:59 +00005433 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005434 offset+=cache_info->columns;
5435 }
cristyc11dace2012-01-24 16:39:46 +00005436 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5437 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005438 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005439 {
5440 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5441 cache_info->cache_filename);
5442 return(MagickFalse);
5443 }
5444 break;
5445 }
5446 default:
5447 break;
5448 }
5449 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005450 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005451 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005452 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005453 nexus_info->region.width,(double) nexus_info->region.height,(double)
5454 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005455 return(MagickTrue);
5456}