blob: 03b4af4b3d41e6a00662fe13b144a52eb96a649b [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);
cristya26c6622012-02-14 14:00:20 +00002862 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2863 if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
2864 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002865 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002866 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2867 cache_info->nexus_info[id]);
2868 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002869}
2870
2871/*
2872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2873% %
2874% %
2875% %
2876+ 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 %
2877% %
2878% %
2879% %
2880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2881%
2882% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2883% pixel cache as defined by the geometry parameters. A pointer to the pixels
2884% is returned if the pixels are transferred, otherwise a NULL is returned.
2885%
2886% The format of the GetVirtualPixelsFromNexus() method is:
2887%
cristy4c08aed2011-07-01 19:47:50 +00002888% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002889% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002890% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2891% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002892%
2893% A description of each parameter follows:
2894%
2895% o image: the image.
2896%
2897% o virtual_pixel_method: the virtual pixel method.
2898%
2899% o x,y,columns,rows: These values define the perimeter of a region of
2900% pixels.
2901%
2902% o nexus_info: the cache nexus to acquire.
2903%
2904% o exception: return any errors or warnings in this structure.
2905%
2906*/
2907
cristybb503372010-05-27 20:51:26 +00002908static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002909 DitherMatrix[64] =
2910 {
2911 0, 48, 12, 60, 3, 51, 15, 63,
2912 32, 16, 44, 28, 35, 19, 47, 31,
2913 8, 56, 4, 52, 11, 59, 7, 55,
2914 40, 24, 36, 20, 43, 27, 39, 23,
2915 2, 50, 14, 62, 1, 49, 13, 61,
2916 34, 18, 46, 30, 33, 17, 45, 29,
2917 10, 58, 6, 54, 9, 57, 5, 53,
2918 42, 26, 38, 22, 41, 25, 37, 21
2919 };
2920
cristybb503372010-05-27 20:51:26 +00002921static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002922{
cristybb503372010-05-27 20:51:26 +00002923 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002924 index;
2925
2926 index=x+DitherMatrix[x & 0x07]-32L;
2927 if (index < 0L)
2928 return(0L);
cristybb503372010-05-27 20:51:26 +00002929 if (index >= (ssize_t) columns)
2930 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002931 return(index);
2932}
2933
cristybb503372010-05-27 20:51:26 +00002934static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002935{
cristybb503372010-05-27 20:51:26 +00002936 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002937 index;
2938
2939 index=y+DitherMatrix[y & 0x07]-32L;
2940 if (index < 0L)
2941 return(0L);
cristybb503372010-05-27 20:51:26 +00002942 if (index >= (ssize_t) rows)
2943 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002944 return(index);
2945}
2946
cristybb503372010-05-27 20:51:26 +00002947static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002948{
2949 if (x < 0L)
2950 return(0L);
cristybb503372010-05-27 20:51:26 +00002951 if (x >= (ssize_t) columns)
2952 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002953 return(x);
2954}
2955
cristybb503372010-05-27 20:51:26 +00002956static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002957{
2958 if (y < 0L)
2959 return(0L);
cristybb503372010-05-27 20:51:26 +00002960 if (y >= (ssize_t) rows)
2961 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002962 return(y);
2963}
2964
cristybb503372010-05-27 20:51:26 +00002965static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002966{
cristybb503372010-05-27 20:51:26 +00002967 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002968}
2969
cristybb503372010-05-27 20:51:26 +00002970static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002971{
cristybb503372010-05-27 20:51:26 +00002972 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002973}
2974
cristybb503372010-05-27 20:51:26 +00002975static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2976 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002977{
2978 MagickModulo
2979 modulo;
2980
cristy6162bb42011-07-18 11:34:09 +00002981 /*
2982 Compute the remainder of dividing offset by extent. It returns not only
2983 the quotient (tile the offset falls in) but also the positive remainer
2984 within that tile such that 0 <= remainder < extent. This method is
2985 essentially a ldiv() using a floored modulo division rather than the
2986 normal default truncated modulo division.
2987 */
cristybb503372010-05-27 20:51:26 +00002988 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002989 if (offset < 0L)
2990 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00002991 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002992 return(modulo);
2993}
2994
cristya6577ff2011-09-02 19:54:26 +00002995MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002996 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2997 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00002998 ExceptionInfo *exception)
2999{
3000 CacheInfo
3001 *cache_info;
3002
3003 MagickOffsetType
3004 offset;
3005
3006 MagickSizeType
3007 length,
3008 number_pixels;
3009
3010 NexusInfo
3011 **virtual_nexus;
3012
cristy4c08aed2011-07-01 19:47:50 +00003013 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003014 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003015 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003016
3017 RectangleInfo
3018 region;
3019
cristy4c08aed2011-07-01 19:47:50 +00003020 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003021 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003022
cristy4c08aed2011-07-01 19:47:50 +00003023 register const void
3024 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003025
cristy4c08aed2011-07-01 19:47:50 +00003026 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003027 *restrict q;
3028
cristybb503372010-05-27 20:51:26 +00003029 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003030 i,
3031 u;
cristy3ed852e2009-09-05 21:47:34 +00003032
cristy4c08aed2011-07-01 19:47:50 +00003033 register unsigned char
3034 *restrict s;
3035
cristy105ba3c2011-07-18 02:28:38 +00003036 ssize_t
3037 v;
3038
cristy4c08aed2011-07-01 19:47:50 +00003039 void
cristy105ba3c2011-07-18 02:28:38 +00003040 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003041
cristy3ed852e2009-09-05 21:47:34 +00003042 /*
3043 Acquire pixels.
3044 */
cristye7cc7cf2010-09-21 13:26:47 +00003045 assert(image != (const Image *) NULL);
3046 assert(image->signature == MagickSignature);
3047 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003048 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003049 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003050 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003051 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003052 region.x=x;
3053 region.y=y;
3054 region.width=columns;
3055 region.height=rows;
3056 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003057 if (pixels == (Quantum *) NULL)
3058 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003059 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003060 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3061 nexus_info->region.x;
3062 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3063 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003064 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3065 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003066 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3067 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003068 {
3069 MagickBooleanType
3070 status;
3071
3072 /*
3073 Pixel request is inside cache extents.
3074 */
cristy4c08aed2011-07-01 19:47:50 +00003075 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003076 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003077 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3078 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003079 return((const Quantum *) NULL);
3080 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003081 {
cristy4c08aed2011-07-01 19:47:50 +00003082 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003083 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003084 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003085 }
cristyacd2ed22011-08-30 01:44:23 +00003086 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003087 }
3088 /*
3089 Pixel request is outside cache extents.
3090 */
cristy4c08aed2011-07-01 19:47:50 +00003091 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003092 virtual_nexus=AcquirePixelCacheNexus(1);
3093 if (virtual_nexus == (NexusInfo **) NULL)
3094 {
cristy4c08aed2011-07-01 19:47:50 +00003095 if (virtual_nexus != (NexusInfo **) NULL)
3096 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003097 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3098 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003099 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003100 }
cristy105ba3c2011-07-18 02:28:38 +00003101 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3102 sizeof(*virtual_pixel));
3103 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003104 switch (virtual_pixel_method)
3105 {
cristy4c08aed2011-07-01 19:47:50 +00003106 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003107 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003108 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003109 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003110 case MaskVirtualPixelMethod:
3111 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003112 case EdgeVirtualPixelMethod:
3113 case CheckerTileVirtualPixelMethod:
3114 case HorizontalTileVirtualPixelMethod:
3115 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003116 {
cristy4c08aed2011-07-01 19:47:50 +00003117 if (cache_info->metacontent_extent != 0)
3118 {
cristy6162bb42011-07-18 11:34:09 +00003119 /*
3120 Acquire a metacontent buffer.
3121 */
cristya64b85d2011-09-14 01:02:31 +00003122 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003123 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003124 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003125 {
cristy4c08aed2011-07-01 19:47:50 +00003126 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3127 (void) ThrowMagickException(exception,GetMagickModule(),
3128 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3129 return((const Quantum *) NULL);
3130 }
cristy105ba3c2011-07-18 02:28:38 +00003131 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003132 cache_info->metacontent_extent);
3133 }
3134 switch (virtual_pixel_method)
3135 {
3136 case BlackVirtualPixelMethod:
3137 {
cristy30301712011-07-18 15:06:51 +00003138 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3139 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003140 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3141 break;
3142 }
3143 case GrayVirtualPixelMethod:
3144 {
cristy30301712011-07-18 15:06:51 +00003145 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003146 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3147 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003148 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3149 break;
3150 }
3151 case TransparentVirtualPixelMethod:
3152 {
cristy30301712011-07-18 15:06:51 +00003153 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3154 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003155 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3156 break;
3157 }
3158 case MaskVirtualPixelMethod:
3159 case WhiteVirtualPixelMethod:
3160 {
cristy30301712011-07-18 15:06:51 +00003161 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3162 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003163 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3164 break;
3165 }
3166 default:
3167 {
cristy9e0719b2011-12-29 03:45:45 +00003168 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3169 virtual_pixel);
3170 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3171 virtual_pixel);
3172 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3173 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003174 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3175 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003176 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3177 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003178 break;
3179 }
3180 }
cristy3ed852e2009-09-05 21:47:34 +00003181 break;
3182 }
3183 default:
cristy3ed852e2009-09-05 21:47:34 +00003184 break;
cristy3ed852e2009-09-05 21:47:34 +00003185 }
cristybb503372010-05-27 20:51:26 +00003186 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003187 {
cristybb503372010-05-27 20:51:26 +00003188 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003189 {
3190 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003191 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003192 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3193 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003194 {
3195 MagickModulo
3196 x_modulo,
3197 y_modulo;
3198
3199 /*
3200 Transfer a single pixel.
3201 */
3202 length=(MagickSizeType) 1;
3203 switch (virtual_pixel_method)
3204 {
cristy3ed852e2009-09-05 21:47:34 +00003205 default:
3206 {
3207 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003208 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003209 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003210 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003211 break;
3212 }
3213 case RandomVirtualPixelMethod:
3214 {
3215 if (cache_info->random_info == (RandomInfo *) NULL)
3216 cache_info->random_info=AcquireRandomInfo();
3217 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003218 RandomX(cache_info->random_info,cache_info->columns),
3219 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003220 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003221 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003222 break;
3223 }
3224 case DitherVirtualPixelMethod:
3225 {
3226 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003227 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003228 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003229 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003230 break;
3231 }
3232 case TileVirtualPixelMethod:
3233 {
3234 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3235 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3236 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003237 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003238 exception);
cristy4c08aed2011-07-01 19:47:50 +00003239 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003240 break;
3241 }
3242 case MirrorVirtualPixelMethod:
3243 {
3244 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3245 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003246 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003247 x_modulo.remainder-1L;
3248 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3249 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003250 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003251 y_modulo.remainder-1L;
3252 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003253 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003254 exception);
cristy4c08aed2011-07-01 19:47:50 +00003255 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003256 break;
3257 }
3258 case HorizontalTileEdgeVirtualPixelMethod:
3259 {
3260 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3261 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003262 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003263 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003264 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003265 break;
3266 }
3267 case VerticalTileEdgeVirtualPixelMethod:
3268 {
3269 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3270 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003271 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003272 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003273 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3274 break;
3275 }
3276 case BackgroundVirtualPixelMethod:
3277 case BlackVirtualPixelMethod:
3278 case GrayVirtualPixelMethod:
3279 case TransparentVirtualPixelMethod:
3280 case MaskVirtualPixelMethod:
3281 case WhiteVirtualPixelMethod:
3282 {
3283 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003284 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003285 break;
3286 }
3287 case EdgeVirtualPixelMethod:
3288 case CheckerTileVirtualPixelMethod:
3289 {
3290 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3291 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3292 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3293 {
3294 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003295 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003296 break;
3297 }
3298 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3299 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3300 exception);
3301 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3302 break;
3303 }
3304 case HorizontalTileVirtualPixelMethod:
3305 {
3306 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3307 {
3308 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003309 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003310 break;
3311 }
3312 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3313 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3314 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3315 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3316 exception);
3317 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3318 break;
3319 }
3320 case VerticalTileVirtualPixelMethod:
3321 {
3322 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3323 {
3324 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003325 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003326 break;
3327 }
3328 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3329 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3330 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3331 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3332 exception);
3333 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003334 break;
3335 }
3336 }
cristy4c08aed2011-07-01 19:47:50 +00003337 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003338 break;
cristyed231572011-07-14 02:18:59 +00003339 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003340 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003341 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003342 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003343 {
3344 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3345 s+=cache_info->metacontent_extent;
3346 }
cristy3ed852e2009-09-05 21:47:34 +00003347 continue;
3348 }
3349 /*
3350 Transfer a run of pixels.
3351 */
cristy4c08aed2011-07-01 19:47:50 +00003352 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3353 length,1UL,*virtual_nexus,exception);
3354 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003355 break;
cristy4c08aed2011-07-01 19:47:50 +00003356 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003357 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3358 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003359 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003360 {
cristy4c08aed2011-07-01 19:47:50 +00003361 (void) memcpy(s,r,(size_t) length);
3362 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003363 }
3364 }
3365 }
cristy4c08aed2011-07-01 19:47:50 +00003366 /*
3367 Free resources.
3368 */
cristy105ba3c2011-07-18 02:28:38 +00003369 if (virtual_metacontent != (void *) NULL)
3370 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003371 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3372 return(pixels);
3373}
3374
3375/*
3376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3377% %
3378% %
3379% %
3380+ G e t V i r t u a l P i x e l C a c h e %
3381% %
3382% %
3383% %
3384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3385%
3386% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3387% cache as defined by the geometry parameters. A pointer to the pixels
3388% is returned if the pixels are transferred, otherwise a NULL is returned.
3389%
3390% The format of the GetVirtualPixelCache() method is:
3391%
cristy4c08aed2011-07-01 19:47:50 +00003392% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003393% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3394% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003395% ExceptionInfo *exception)
3396%
3397% A description of each parameter follows:
3398%
3399% o image: the image.
3400%
3401% o virtual_pixel_method: the virtual pixel method.
3402%
3403% o x,y,columns,rows: These values define the perimeter of a region of
3404% pixels.
3405%
3406% o exception: return any errors or warnings in this structure.
3407%
3408*/
cristy4c08aed2011-07-01 19:47:50 +00003409static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003410 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3411 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003412{
3413 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003414 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003415
cristy5c9e6f22010-09-17 17:31:01 +00003416 const int
3417 id = GetOpenMPThreadId();
3418
cristy4c08aed2011-07-01 19:47:50 +00003419 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003420 *p;
cristy4c08aed2011-07-01 19:47:50 +00003421
cristye7cc7cf2010-09-21 13:26:47 +00003422 assert(image != (const Image *) NULL);
3423 assert(image->signature == MagickSignature);
3424 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003425 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003426 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003427 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003428 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003429 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003430 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003431}
3432
3433/*
3434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3435% %
3436% %
3437% %
3438% G e t V i r t u a l P i x e l Q u e u e %
3439% %
3440% %
3441% %
3442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3443%
cristy4c08aed2011-07-01 19:47:50 +00003444% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3445% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003446%
3447% The format of the GetVirtualPixelQueue() method is:
3448%
cristy4c08aed2011-07-01 19:47:50 +00003449% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003450%
3451% A description of each parameter follows:
3452%
3453% o image: the image.
3454%
3455*/
cristy4c08aed2011-07-01 19:47:50 +00003456MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003457{
3458 CacheInfo
3459 *cache_info;
3460
cristy2036f5c2010-09-19 21:18:17 +00003461 const int
3462 id = GetOpenMPThreadId();
3463
cristy3ed852e2009-09-05 21:47:34 +00003464 assert(image != (const Image *) NULL);
3465 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003466 assert(image->cache != (Cache) NULL);
3467 cache_info=(CacheInfo *) image->cache;
3468 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003469 if (cache_info->methods.get_virtual_pixels_handler !=
3470 (GetVirtualPixelsHandler) NULL)
3471 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003472 assert(id < (int) cache_info->number_threads);
3473 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003474}
3475
3476/*
3477%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3478% %
3479% %
3480% %
3481% G e t V i r t u a l P i x e l s %
3482% %
3483% %
3484% %
3485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3486%
3487% GetVirtualPixels() returns an immutable pixel region. If the
3488% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003489% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003490% copy of the pixels or it may point to the original pixels in memory.
3491% Performance is maximized if the selected region is part of one row, or one
3492% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003493% (without a copy) if the image is in memory, or in a memory-mapped file. The
3494% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003495%
3496% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003497% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3498% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3499% access the meta-content (of type void) corresponding to the the
3500% region.
cristy3ed852e2009-09-05 21:47:34 +00003501%
3502% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3503%
3504% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3505% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3506% GetCacheViewAuthenticPixels() instead.
3507%
3508% The format of the GetVirtualPixels() method is:
3509%
cristy4c08aed2011-07-01 19:47:50 +00003510% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003511% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003512% ExceptionInfo *exception)
3513%
3514% A description of each parameter follows:
3515%
3516% o image: the image.
3517%
3518% o x,y,columns,rows: These values define the perimeter of a region of
3519% pixels.
3520%
3521% o exception: return any errors or warnings in this structure.
3522%
3523*/
cristy4c08aed2011-07-01 19:47:50 +00003524MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003525 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3526 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003527{
3528 CacheInfo
3529 *cache_info;
3530
cristy2036f5c2010-09-19 21:18:17 +00003531 const int
3532 id = GetOpenMPThreadId();
3533
cristy4c08aed2011-07-01 19:47:50 +00003534 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003535 *p;
cristy4c08aed2011-07-01 19:47:50 +00003536
cristy3ed852e2009-09-05 21:47:34 +00003537 assert(image != (const Image *) NULL);
3538 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003539 assert(image->cache != (Cache) NULL);
3540 cache_info=(CacheInfo *) image->cache;
3541 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003542 if (cache_info->methods.get_virtual_pixel_handler !=
3543 (GetVirtualPixelHandler) NULL)
3544 return(cache_info->methods.get_virtual_pixel_handler(image,
3545 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003546 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003547 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003548 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003549 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003550}
3551
3552/*
3553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3554% %
3555% %
3556% %
3557+ 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 %
3558% %
3559% %
3560% %
3561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562%
cristy4c08aed2011-07-01 19:47:50 +00003563% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3564% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003565%
3566% The format of the GetVirtualPixelsCache() method is:
3567%
cristy4c08aed2011-07-01 19:47:50 +00003568% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003569%
3570% A description of each parameter follows:
3571%
3572% o image: the image.
3573%
3574*/
cristy4c08aed2011-07-01 19:47:50 +00003575static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003576{
3577 CacheInfo
3578 *cache_info;
3579
cristy5c9e6f22010-09-17 17:31:01 +00003580 const int
3581 id = GetOpenMPThreadId();
3582
cristye7cc7cf2010-09-21 13:26:47 +00003583 assert(image != (const Image *) NULL);
3584 assert(image->signature == MagickSignature);
3585 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003586 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003587 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003588 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003589 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003590}
3591
3592/*
3593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3594% %
3595% %
3596% %
3597+ G e t V i r t u a l P i x e l s N e x u s %
3598% %
3599% %
3600% %
3601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3602%
3603% GetVirtualPixelsNexus() returns the pixels associated with the specified
3604% cache nexus.
3605%
3606% The format of the GetVirtualPixelsNexus() method is:
3607%
cristy4c08aed2011-07-01 19:47:50 +00003608% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003609% NexusInfo *nexus_info)
3610%
3611% A description of each parameter follows:
3612%
3613% o cache: the pixel cache.
3614%
3615% o nexus_info: the cache nexus to return the colormap pixels.
3616%
3617*/
cristya6577ff2011-09-02 19:54:26 +00003618MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003619 NexusInfo *nexus_info)
3620{
3621 CacheInfo
3622 *cache_info;
3623
cristye7cc7cf2010-09-21 13:26:47 +00003624 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003625 cache_info=(CacheInfo *) cache;
3626 assert(cache_info->signature == MagickSignature);
3627 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003628 return((Quantum *) NULL);
3629 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003630}
3631
3632/*
3633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3634% %
3635% %
3636% %
cristy3ed852e2009-09-05 21:47:34 +00003637+ O p e n P i x e l C a c h e %
3638% %
3639% %
3640% %
3641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3642%
3643% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3644% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003645% metacontent, and memory mapping the cache if it is disk based. The cache
3646% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003647%
3648% The format of the OpenPixelCache() method is:
3649%
3650% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3651% ExceptionInfo *exception)
3652%
3653% A description of each parameter follows:
3654%
3655% o image: the image.
3656%
3657% o mode: ReadMode, WriteMode, or IOMode.
3658%
3659% o exception: return any errors or warnings in this structure.
3660%
3661*/
3662
cristyd43a46b2010-01-21 02:13:41 +00003663static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003664{
3665 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003666 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003667 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003668 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003669 {
3670 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003671 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003672 cache_info->length);
3673 }
3674}
3675
3676static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3677{
3678 CacheInfo
3679 *cache_info;
3680
3681 MagickOffsetType
3682 count,
3683 extent,
3684 offset;
3685
3686 cache_info=(CacheInfo *) image->cache;
3687 if (image->debug != MagickFalse)
3688 {
3689 char
3690 format[MaxTextExtent],
3691 message[MaxTextExtent];
3692
cristyb9080c92009-12-01 20:13:26 +00003693 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003694 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003695 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003696 cache_info->cache_filename,cache_info->file,format);
3697 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3698 }
3699 if (length != (MagickSizeType) ((MagickOffsetType) length))
3700 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003701 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003702 if (extent < 0)
3703 return(MagickFalse);
3704 if ((MagickSizeType) extent >= length)
3705 return(MagickTrue);
3706 offset=(MagickOffsetType) length-1;
3707 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3708 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3709}
3710
3711static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3712 ExceptionInfo *exception)
3713{
cristy3ed852e2009-09-05 21:47:34 +00003714 CacheInfo
3715 *cache_info,
3716 source_info;
3717
cristyf3a6a9d2010-11-07 21:02:56 +00003718 char
3719 format[MaxTextExtent],
3720 message[MaxTextExtent];
3721
cristy4c08aed2011-07-01 19:47:50 +00003722 MagickBooleanType
3723 status;
3724
cristy3ed852e2009-09-05 21:47:34 +00003725 MagickSizeType
3726 length,
3727 number_pixels;
3728
cristy3b8fe922011-12-29 18:56:23 +00003729 PixelChannelMap
3730 *p,
3731 *q;
3732
cristy3ed852e2009-09-05 21:47:34 +00003733 size_t
cristye076a6e2010-08-15 19:59:43 +00003734 columns,
cristy3ed852e2009-09-05 21:47:34 +00003735 packet_size;
3736
cristye7cc7cf2010-09-21 13:26:47 +00003737 assert(image != (const Image *) NULL);
3738 assert(image->signature == MagickSignature);
3739 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003740 if (image->debug != MagickFalse)
3741 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3742 if ((image->columns == 0) || (image->rows == 0))
3743 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3744 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003745 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003746 source_info=(*cache_info);
3747 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003748 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003749 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003750 cache_info->storage_class=image->storage_class;
3751 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003752 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003753 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003754 cache_info->rows=image->rows;
3755 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003756 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003757 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003758 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3759 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003760 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003761 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003762 if (image->ping != MagickFalse)
3763 {
cristy73724512010-04-12 14:43:14 +00003764 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003765 cache_info->pixels=(Quantum *) NULL;
3766 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003767 cache_info->length=0;
3768 return(MagickTrue);
3769 }
cristy3ed852e2009-09-05 21:47:34 +00003770 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003771 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003772 if (image->metacontent_extent != 0)
3773 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003774 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003775 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003776 if (cache_info->columns != columns)
3777 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3778 image->filename);
3779 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00003780 p=cache_info->channel_map;
3781 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00003782 if ((cache_info->type != UndefinedCache) &&
3783 (cache_info->columns <= source_info.columns) &&
3784 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00003785 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00003786 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00003787 (cache_info->metacontent_extent <= source_info.metacontent_extent))
3788 {
3789 /*
3790 Inline pixel cache clone optimization.
3791 */
3792 if ((cache_info->columns == source_info.columns) &&
3793 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00003794 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00003795 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00003796 (cache_info->metacontent_extent == source_info.metacontent_extent))
3797 return(MagickTrue);
3798 return(ClonePixelCachePixels(cache_info,&source_info,exception));
3799 }
cristy3ed852e2009-09-05 21:47:34 +00003800 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003801 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003802 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003803 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3804 {
3805 status=AcquireMagickResource(MemoryResource,cache_info->length);
3806 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3807 (cache_info->type == MemoryCache))
3808 {
cristyd43a46b2010-01-21 02:13:41 +00003809 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003810 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003811 cache_info->pixels=source_info.pixels;
3812 else
3813 {
3814 /*
3815 Create memory pixel cache.
3816 */
cristy4c08aed2011-07-01 19:47:50 +00003817 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003818 if (image->debug != MagickFalse)
3819 {
cristy32cacff2011-12-31 03:36:27 +00003820 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003821 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003822 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3823 cache_info->filename,cache_info->mapped != MagickFalse ?
3824 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003825 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003826 format);
cristy3ed852e2009-09-05 21:47:34 +00003827 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3828 message);
3829 }
cristy3ed852e2009-09-05 21:47:34 +00003830 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003831 cache_info->metacontent=(void *) NULL;
3832 if (cache_info->metacontent_extent != 0)
3833 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003834 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003835 if ((source_info.storage_class != UndefinedClass) &&
3836 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003837 {
cristy4c08aed2011-07-01 19:47:50 +00003838 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003839 exception);
3840 RelinquishPixelCachePixels(&source_info);
3841 }
cristy4c08aed2011-07-01 19:47:50 +00003842 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003843 }
3844 }
3845 RelinquishMagickResource(MemoryResource,cache_info->length);
3846 }
3847 /*
3848 Create pixel cache on disk.
3849 */
3850 status=AcquireMagickResource(DiskResource,cache_info->length);
3851 if (status == MagickFalse)
3852 {
3853 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3854 "CacheResourcesExhausted","`%s'",image->filename);
3855 return(MagickFalse);
3856 }
cristy413f1302012-01-01 17:48:27 +00003857 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3858 {
3859 (void) ClosePixelCacheOnDisk(cache_info);
3860 *cache_info->cache_filename='\0';
3861 }
cristy3ed852e2009-09-05 21:47:34 +00003862 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3863 {
3864 RelinquishMagickResource(DiskResource,cache_info->length);
3865 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3866 image->filename);
3867 return(MagickFalse);
3868 }
3869 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3870 cache_info->length);
3871 if (status == MagickFalse)
3872 {
3873 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3874 image->filename);
3875 return(MagickFalse);
3876 }
cristyed231572011-07-14 02:18:59 +00003877 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003878 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003879 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003880 cache_info->type=DiskCache;
3881 else
3882 {
3883 status=AcquireMagickResource(MapResource,cache_info->length);
3884 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3885 (cache_info->type != MemoryCache))
3886 cache_info->type=DiskCache;
3887 else
3888 {
cristy4c08aed2011-07-01 19:47:50 +00003889 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003890 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003891 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003892 {
cristy3ed852e2009-09-05 21:47:34 +00003893 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003894 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003895 }
3896 else
3897 {
3898 /*
3899 Create file-backed memory-mapped pixel cache.
3900 */
cristy4c08aed2011-07-01 19:47:50 +00003901 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003902 (void) ClosePixelCacheOnDisk(cache_info);
3903 cache_info->type=MapCache;
3904 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003905 cache_info->metacontent=(void *) NULL;
3906 if (cache_info->metacontent_extent != 0)
3907 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003908 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003909 if ((source_info.storage_class != UndefinedClass) &&
3910 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003911 {
3912 status=ClonePixelCachePixels(cache_info,&source_info,
3913 exception);
3914 RelinquishPixelCachePixels(&source_info);
3915 }
3916 if (image->debug != MagickFalse)
3917 {
cristy413f1302012-01-01 17:48:27 +00003918 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003919 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003920 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003921 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003922 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003923 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003924 format);
cristy3ed852e2009-09-05 21:47:34 +00003925 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3926 message);
3927 }
cristy4c08aed2011-07-01 19:47:50 +00003928 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003929 }
3930 }
3931 RelinquishMagickResource(MapResource,cache_info->length);
3932 }
cristy4c08aed2011-07-01 19:47:50 +00003933 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003934 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003935 {
3936 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3937 RelinquishPixelCachePixels(&source_info);
3938 }
3939 if (image->debug != MagickFalse)
3940 {
cristyb9080c92009-12-01 20:13:26 +00003941 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003942 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003943 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003944 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003945 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003946 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003947 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3948 }
cristy4c08aed2011-07-01 19:47:50 +00003949 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003950}
3951
3952/*
3953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3954% %
3955% %
3956% %
3957+ P e r s i s t P i x e l C a c h e %
3958% %
3959% %
3960% %
3961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3962%
3963% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3964% persistent pixel cache is one that resides on disk and is not destroyed
3965% when the program exits.
3966%
3967% The format of the PersistPixelCache() method is:
3968%
3969% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3970% const MagickBooleanType attach,MagickOffsetType *offset,
3971% ExceptionInfo *exception)
3972%
3973% A description of each parameter follows:
3974%
3975% o image: the image.
3976%
3977% o filename: the persistent pixel cache filename.
3978%
cristyf3a6a9d2010-11-07 21:02:56 +00003979% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003980%
cristy3ed852e2009-09-05 21:47:34 +00003981% o initialize: A value other than zero initializes the persistent pixel
3982% cache.
3983%
3984% o offset: the offset in the persistent cache to store pixels.
3985%
3986% o exception: return any errors or warnings in this structure.
3987%
3988*/
3989MagickExport MagickBooleanType PersistPixelCache(Image *image,
3990 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3991 ExceptionInfo *exception)
3992{
3993 CacheInfo
3994 *cache_info,
3995 *clone_info;
3996
3997 Image
3998 clone_image;
3999
cristy3ed852e2009-09-05 21:47:34 +00004000 MagickBooleanType
4001 status;
4002
cristye076a6e2010-08-15 19:59:43 +00004003 ssize_t
4004 page_size;
4005
cristy3ed852e2009-09-05 21:47:34 +00004006 assert(image != (Image *) NULL);
4007 assert(image->signature == MagickSignature);
4008 if (image->debug != MagickFalse)
4009 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4010 assert(image->cache != (void *) NULL);
4011 assert(filename != (const char *) NULL);
4012 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004013 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004014 cache_info=(CacheInfo *) image->cache;
4015 assert(cache_info->signature == MagickSignature);
4016 if (attach != MagickFalse)
4017 {
4018 /*
cristy01b7eb02009-09-10 23:10:14 +00004019 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004020 */
4021 if (image->debug != MagickFalse)
4022 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004023 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004024 (void) CopyMagickString(cache_info->cache_filename,filename,
4025 MaxTextExtent);
4026 cache_info->type=DiskCache;
4027 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004028 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004029 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004030 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004031 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004032 }
cristy01b7eb02009-09-10 23:10:14 +00004033 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4034 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004035 {
cristyf84a1932010-01-03 18:00:18 +00004036 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004037 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004038 (cache_info->reference_count == 1))
4039 {
4040 int
4041 status;
4042
4043 /*
cristy01b7eb02009-09-10 23:10:14 +00004044 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004045 */
cristy320684d2011-09-23 14:55:47 +00004046 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004047 if (status == 0)
4048 {
4049 (void) CopyMagickString(cache_info->cache_filename,filename,
4050 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004051 *offset+=cache_info->length+page_size-(cache_info->length %
4052 page_size);
cristyf84a1932010-01-03 18:00:18 +00004053 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004054 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004055 if (image->debug != MagickFalse)
4056 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4057 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004058 return(MagickTrue);
4059 }
4060 }
cristyf84a1932010-01-03 18:00:18 +00004061 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004062 }
4063 /*
cristy01b7eb02009-09-10 23:10:14 +00004064 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004065 */
4066 clone_image=(*image);
4067 clone_info=(CacheInfo *) clone_image.cache;
4068 image->cache=ClonePixelCache(cache_info);
4069 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4070 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4071 cache_info->type=DiskCache;
4072 cache_info->offset=(*offset);
4073 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004074 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004075 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004076 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004077 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004078 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4079 return(status);
4080}
4081
4082/*
4083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4084% %
4085% %
4086% %
cristyc11dace2012-01-24 16:39:46 +00004087+ 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 +00004088% %
4089% %
4090% %
4091%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4092%
cristyc11dace2012-01-24 16:39:46 +00004093% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4094% defined by the region rectangle and returns a pointer to the region. This
4095% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004096% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4097% pixels are transferred, otherwise a NULL is returned.
4098%
cristyc11dace2012-01-24 16:39:46 +00004099% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004100%
cristyc11dace2012-01-24 16:39:46 +00004101% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004102% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004103% const MagickBooleanType clone,NexusInfo *nexus_info,
4104% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004105%
4106% A description of each parameter follows:
4107%
4108% o image: the image.
4109%
4110% o x,y,columns,rows: These values define the perimeter of a region of
4111% pixels.
4112%
4113% o nexus_info: the cache nexus to set.
4114%
cristy65dbf172011-10-06 17:32:04 +00004115% o clone: clone the pixel cache.
4116%
cristy3ed852e2009-09-05 21:47:34 +00004117% o exception: return any errors or warnings in this structure.
4118%
4119*/
cristyc11dace2012-01-24 16:39:46 +00004120MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4121 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004122 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004123{
4124 CacheInfo
4125 *cache_info;
4126
4127 MagickOffsetType
4128 offset;
4129
4130 MagickSizeType
4131 number_pixels;
4132
4133 RectangleInfo
4134 region;
4135
4136 /*
4137 Validate pixel cache geometry.
4138 */
cristye7cc7cf2010-09-21 13:26:47 +00004139 assert(image != (const Image *) NULL);
4140 assert(image->signature == MagickSignature);
4141 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004142 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004143 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004144 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004145 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004146 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4147 {
4148 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4149 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004150 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004151 }
cristybb503372010-05-27 20:51:26 +00004152 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4153 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004154 {
4155 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4156 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004157 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004158 }
4159 offset=(MagickOffsetType) y*cache_info->columns+x;
4160 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004161 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004162 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4163 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4164 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004165 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004166 /*
4167 Return pixel cache.
4168 */
4169 region.x=x;
4170 region.y=y;
4171 region.width=columns;
4172 region.height=rows;
4173 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4174}
4175
4176/*
4177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4178% %
4179% %
4180% %
4181+ 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 %
4182% %
4183% %
4184% %
4185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4186%
4187% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4188% defined by the region rectangle and returns a pointer to the region. This
4189% region is subsequently transferred from the pixel cache with
4190% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4191% pixels are transferred, otherwise a NULL is returned.
4192%
4193% The format of the QueueAuthenticPixelsCache() method is:
4194%
cristy4c08aed2011-07-01 19:47:50 +00004195% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004196% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004197% ExceptionInfo *exception)
4198%
4199% A description of each parameter follows:
4200%
4201% o image: the image.
4202%
4203% o x,y,columns,rows: These values define the perimeter of a region of
4204% pixels.
4205%
4206% o exception: return any errors or warnings in this structure.
4207%
4208*/
cristy4c08aed2011-07-01 19:47:50 +00004209static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004210 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004211 ExceptionInfo *exception)
4212{
4213 CacheInfo
4214 *cache_info;
4215
cristy5c9e6f22010-09-17 17:31:01 +00004216 const int
4217 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004218
cristy4c08aed2011-07-01 19:47:50 +00004219 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004220 *q;
cristy4c08aed2011-07-01 19:47:50 +00004221
cristye7cc7cf2010-09-21 13:26:47 +00004222 assert(image != (const Image *) NULL);
4223 assert(image->signature == MagickSignature);
4224 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004225 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004226 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004227 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004228 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004229 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004230 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004231}
4232
4233/*
4234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4235% %
4236% %
4237% %
4238% Q u e u e A u t h e n t i c P i x e l s %
4239% %
4240% %
4241% %
4242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4243%
4244% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004245% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004246% region is returned, otherwise NULL is returned. The returned pointer may
4247% point to a temporary working buffer for the pixels or it may point to the
4248% final location of the pixels in memory.
4249%
4250% Write-only access means that any existing pixel values corresponding to
4251% the region are ignored. This is useful if the initial image is being
4252% created from scratch, or if the existing pixel values are to be
4253% completely replaced without need to refer to their pre-existing values.
4254% The application is free to read and write the pixel buffer returned by
4255% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4256% initialize the pixel array values. Initializing pixel array values is the
4257% application's responsibility.
4258%
4259% Performance is maximized if the selected region is part of one row, or
4260% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004261% pixels in-place (without a copy) if the image is in memory, or in a
4262% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004263% by the user.
4264%
4265% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004266% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4267% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4268% obtain the meta-content (of type void) corresponding to the region.
4269% Once the Quantum (and/or Quantum) array has been updated, the
4270% changes must be saved back to the underlying image using
4271% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004272%
4273% The format of the QueueAuthenticPixels() method is:
4274%
cristy4c08aed2011-07-01 19:47:50 +00004275% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004276% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004277% ExceptionInfo *exception)
4278%
4279% A description of each parameter follows:
4280%
4281% o image: the image.
4282%
4283% o x,y,columns,rows: These values define the perimeter of a region of
4284% pixels.
4285%
4286% o exception: return any errors or warnings in this structure.
4287%
4288*/
cristy4c08aed2011-07-01 19:47:50 +00004289MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004290 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004291 ExceptionInfo *exception)
4292{
4293 CacheInfo
4294 *cache_info;
4295
cristy2036f5c2010-09-19 21:18:17 +00004296 const int
4297 id = GetOpenMPThreadId();
4298
cristy4c08aed2011-07-01 19:47:50 +00004299 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004300 *q;
cristy4c08aed2011-07-01 19:47:50 +00004301
cristy3ed852e2009-09-05 21:47:34 +00004302 assert(image != (Image *) NULL);
4303 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004304 assert(image->cache != (Cache) NULL);
4305 cache_info=(CacheInfo *) image->cache;
4306 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004307 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004308 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004309 {
cristyc36c8822012-02-14 14:02:36 +00004310 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4311 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004312 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004313 }
cristy2036f5c2010-09-19 21:18:17 +00004314 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004315 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004316 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004317 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004318}
4319
4320/*
4321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4322% %
4323% %
4324% %
cristy4c08aed2011-07-01 19:47:50 +00004325+ 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 +00004326% %
4327% %
4328% %
4329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4330%
cristy4c08aed2011-07-01 19:47:50 +00004331% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004332% the pixel cache.
4333%
cristy4c08aed2011-07-01 19:47:50 +00004334% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004335%
cristy4c08aed2011-07-01 19:47:50 +00004336% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004337% NexusInfo *nexus_info,ExceptionInfo *exception)
4338%
4339% A description of each parameter follows:
4340%
4341% o cache_info: the pixel cache.
4342%
cristy4c08aed2011-07-01 19:47:50 +00004343% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004344%
4345% o exception: return any errors or warnings in this structure.
4346%
4347*/
cristy4c08aed2011-07-01 19:47:50 +00004348static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004349 NexusInfo *nexus_info,ExceptionInfo *exception)
4350{
4351 MagickOffsetType
4352 count,
4353 offset;
4354
4355 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004356 extent,
4357 length;
cristy3ed852e2009-09-05 21:47:34 +00004358
cristybb503372010-05-27 20:51:26 +00004359 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004360 y;
4361
cristy4c08aed2011-07-01 19:47:50 +00004362 register unsigned char
4363 *restrict q;
4364
cristybb503372010-05-27 20:51:26 +00004365 size_t
cristy3ed852e2009-09-05 21:47:34 +00004366 rows;
4367
cristy4c08aed2011-07-01 19:47:50 +00004368 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004369 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004370 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004371 return(MagickTrue);
4372 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4373 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004374 length=(MagickSizeType) nexus_info->region.width*
4375 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004376 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004377 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004378 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004379 switch (cache_info->type)
4380 {
4381 case MemoryCache:
4382 case MapCache:
4383 {
cristy4c08aed2011-07-01 19:47:50 +00004384 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004385 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004386
4387 /*
cristy4c08aed2011-07-01 19:47:50 +00004388 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004389 */
cristydd341db2010-03-04 19:06:38 +00004390 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004391 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004392 {
cristy48078b12010-09-23 17:11:01 +00004393 length=extent;
cristydd341db2010-03-04 19:06:38 +00004394 rows=1UL;
4395 }
cristy4c08aed2011-07-01 19:47:50 +00004396 p=(unsigned char *) cache_info->metacontent+offset*
4397 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004398 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004399 {
cristy8f036fe2010-09-18 02:02:00 +00004400 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004401 p+=cache_info->metacontent_extent*cache_info->columns;
4402 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004403 }
4404 break;
4405 }
4406 case DiskCache:
4407 {
4408 /*
cristy4c08aed2011-07-01 19:47:50 +00004409 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004410 */
4411 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4412 {
4413 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4414 cache_info->cache_filename);
4415 return(MagickFalse);
4416 }
cristydd341db2010-03-04 19:06:38 +00004417 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004418 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004419 {
cristy48078b12010-09-23 17:11:01 +00004420 length=extent;
cristydd341db2010-03-04 19:06:38 +00004421 rows=1UL;
4422 }
cristy48078b12010-09-23 17:11:01 +00004423 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004424 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004425 {
cristy48078b12010-09-23 17:11:01 +00004426 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004427 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004428 cache_info->metacontent_extent,length,(unsigned char *) q);
4429 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004430 break;
4431 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004432 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004433 }
cristyc11dace2012-01-24 16:39:46 +00004434 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4435 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004436 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004437 {
4438 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4439 cache_info->cache_filename);
4440 return(MagickFalse);
4441 }
4442 break;
4443 }
4444 default:
4445 break;
4446 }
4447 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004448 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004449 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004450 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004451 nexus_info->region.width,(double) nexus_info->region.height,(double)
4452 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004453 return(MagickTrue);
4454}
4455
4456/*
4457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4458% %
4459% %
4460% %
4461+ R e a d P i x e l C a c h e P i x e l s %
4462% %
4463% %
4464% %
4465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4466%
4467% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4468% cache.
4469%
4470% The format of the ReadPixelCachePixels() method is:
4471%
4472% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4473% NexusInfo *nexus_info,ExceptionInfo *exception)
4474%
4475% A description of each parameter follows:
4476%
4477% o cache_info: the pixel cache.
4478%
4479% o nexus_info: the cache nexus to read the pixels.
4480%
4481% o exception: return any errors or warnings in this structure.
4482%
4483*/
4484static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4485 NexusInfo *nexus_info,ExceptionInfo *exception)
4486{
4487 MagickOffsetType
4488 count,
4489 offset;
4490
4491 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004492 extent,
4493 length;
cristy3ed852e2009-09-05 21:47:34 +00004494
cristy4c08aed2011-07-01 19:47:50 +00004495 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004496 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004497
cristye076a6e2010-08-15 19:59:43 +00004498 register ssize_t
4499 y;
4500
cristybb503372010-05-27 20:51:26 +00004501 size_t
cristy3ed852e2009-09-05 21:47:34 +00004502 rows;
4503
cristy4c08aed2011-07-01 19:47:50 +00004504 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004505 return(MagickTrue);
4506 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4507 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004508 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004509 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004510 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004511 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004512 q=nexus_info->pixels;
4513 switch (cache_info->type)
4514 {
4515 case MemoryCache:
4516 case MapCache:
4517 {
cristy4c08aed2011-07-01 19:47:50 +00004518 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004519 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004520
4521 /*
4522 Read pixels from memory.
4523 */
cristydd341db2010-03-04 19:06:38 +00004524 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004525 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004526 {
cristy48078b12010-09-23 17:11:01 +00004527 length=extent;
cristydd341db2010-03-04 19:06:38 +00004528 rows=1UL;
4529 }
cristyed231572011-07-14 02:18:59 +00004530 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004531 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004532 {
cristy8f036fe2010-09-18 02:02:00 +00004533 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004534 p+=cache_info->number_channels*cache_info->columns;
4535 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004536 }
4537 break;
4538 }
4539 case DiskCache:
4540 {
4541 /*
4542 Read pixels from disk.
4543 */
4544 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4545 {
4546 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4547 cache_info->cache_filename);
4548 return(MagickFalse);
4549 }
cristydd341db2010-03-04 19:06:38 +00004550 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004551 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004552 {
cristy48078b12010-09-23 17:11:01 +00004553 length=extent;
cristydd341db2010-03-04 19:06:38 +00004554 rows=1UL;
4555 }
cristybb503372010-05-27 20:51:26 +00004556 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004557 {
4558 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004559 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004560 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004561 break;
4562 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004563 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004564 }
cristyc11dace2012-01-24 16:39:46 +00004565 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4566 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004567 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004568 {
4569 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4570 cache_info->cache_filename);
4571 return(MagickFalse);
4572 }
4573 break;
4574 }
4575 default:
4576 break;
4577 }
4578 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004579 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004580 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004581 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004582 nexus_info->region.width,(double) nexus_info->region.height,(double)
4583 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004584 return(MagickTrue);
4585}
4586
4587/*
4588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4589% %
4590% %
4591% %
4592+ R e f e r e n c e P i x e l C a c h e %
4593% %
4594% %
4595% %
4596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4597%
4598% ReferencePixelCache() increments the reference count associated with the
4599% pixel cache returning a pointer to the cache.
4600%
4601% The format of the ReferencePixelCache method is:
4602%
4603% Cache ReferencePixelCache(Cache cache_info)
4604%
4605% A description of each parameter follows:
4606%
4607% o cache_info: the pixel cache.
4608%
4609*/
cristya6577ff2011-09-02 19:54:26 +00004610MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004611{
4612 CacheInfo
4613 *cache_info;
4614
4615 assert(cache != (Cache *) NULL);
4616 cache_info=(CacheInfo *) cache;
4617 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004618 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004619 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004620 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004621 return(cache_info);
4622}
4623
4624/*
4625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4626% %
4627% %
4628% %
4629+ S e t P i x e l C a c h e M e t h o d s %
4630% %
4631% %
4632% %
4633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4634%
4635% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4636%
4637% The format of the SetPixelCacheMethods() method is:
4638%
4639% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4640%
4641% A description of each parameter follows:
4642%
4643% o cache: the pixel cache.
4644%
4645% o cache_methods: Specifies a pointer to a CacheMethods structure.
4646%
4647*/
cristya6577ff2011-09-02 19:54:26 +00004648MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004649{
4650 CacheInfo
4651 *cache_info;
4652
4653 GetOneAuthenticPixelFromHandler
4654 get_one_authentic_pixel_from_handler;
4655
4656 GetOneVirtualPixelFromHandler
4657 get_one_virtual_pixel_from_handler;
4658
4659 /*
4660 Set cache pixel methods.
4661 */
4662 assert(cache != (Cache) NULL);
4663 assert(cache_methods != (CacheMethods *) NULL);
4664 cache_info=(CacheInfo *) cache;
4665 assert(cache_info->signature == MagickSignature);
4666 if (cache_info->debug != MagickFalse)
4667 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4668 cache_info->filename);
4669 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4670 cache_info->methods.get_virtual_pixel_handler=
4671 cache_methods->get_virtual_pixel_handler;
4672 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4673 cache_info->methods.destroy_pixel_handler=
4674 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004675 if (cache_methods->get_virtual_metacontent_from_handler !=
4676 (GetVirtualMetacontentFromHandler) NULL)
4677 cache_info->methods.get_virtual_metacontent_from_handler=
4678 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004679 if (cache_methods->get_authentic_pixels_handler !=
4680 (GetAuthenticPixelsHandler) NULL)
4681 cache_info->methods.get_authentic_pixels_handler=
4682 cache_methods->get_authentic_pixels_handler;
4683 if (cache_methods->queue_authentic_pixels_handler !=
4684 (QueueAuthenticPixelsHandler) NULL)
4685 cache_info->methods.queue_authentic_pixels_handler=
4686 cache_methods->queue_authentic_pixels_handler;
4687 if (cache_methods->sync_authentic_pixels_handler !=
4688 (SyncAuthenticPixelsHandler) NULL)
4689 cache_info->methods.sync_authentic_pixels_handler=
4690 cache_methods->sync_authentic_pixels_handler;
4691 if (cache_methods->get_authentic_pixels_from_handler !=
4692 (GetAuthenticPixelsFromHandler) NULL)
4693 cache_info->methods.get_authentic_pixels_from_handler=
4694 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004695 if (cache_methods->get_authentic_metacontent_from_handler !=
4696 (GetAuthenticMetacontentFromHandler) NULL)
4697 cache_info->methods.get_authentic_metacontent_from_handler=
4698 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004699 get_one_virtual_pixel_from_handler=
4700 cache_info->methods.get_one_virtual_pixel_from_handler;
4701 if (get_one_virtual_pixel_from_handler !=
4702 (GetOneVirtualPixelFromHandler) NULL)
4703 cache_info->methods.get_one_virtual_pixel_from_handler=
4704 cache_methods->get_one_virtual_pixel_from_handler;
4705 get_one_authentic_pixel_from_handler=
4706 cache_methods->get_one_authentic_pixel_from_handler;
4707 if (get_one_authentic_pixel_from_handler !=
4708 (GetOneAuthenticPixelFromHandler) NULL)
4709 cache_info->methods.get_one_authentic_pixel_from_handler=
4710 cache_methods->get_one_authentic_pixel_from_handler;
4711}
4712
4713/*
4714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4715% %
4716% %
4717% %
4718+ S e t P i x e l C a c h e N e x u s P i x e l s %
4719% %
4720% %
4721% %
4722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4723%
4724% SetPixelCacheNexusPixels() defines the region of the cache for the
4725% specified cache nexus.
4726%
4727% The format of the SetPixelCacheNexusPixels() method is:
4728%
cristy4c08aed2011-07-01 19:47:50 +00004729% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004730% const RectangleInfo *region,NexusInfo *nexus_info,
4731% ExceptionInfo *exception)
4732%
4733% A description of each parameter follows:
4734%
4735% o image: the image.
4736%
4737% o region: A pointer to the RectangleInfo structure that defines the
4738% region of this particular cache nexus.
4739%
4740% o nexus_info: the cache nexus to set.
4741%
4742% o exception: return any errors or warnings in this structure.
4743%
4744*/
cristyabd6e372010-09-15 19:11:26 +00004745
4746static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4747 NexusInfo *nexus_info,ExceptionInfo *exception)
4748{
4749 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4750 return(MagickFalse);
4751 nexus_info->mapped=MagickFalse;
cristy7dc8ac52012-01-10 20:14:52 +00004752 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004753 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004754 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004755 {
4756 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004757 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004758 nexus_info->length);
4759 }
cristy4c08aed2011-07-01 19:47:50 +00004760 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004761 {
4762 (void) ThrowMagickException(exception,GetMagickModule(),
4763 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4764 cache_info->filename);
4765 return(MagickFalse);
4766 }
4767 return(MagickTrue);
4768}
4769
cristy4c08aed2011-07-01 19:47:50 +00004770static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004771 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4772{
4773 CacheInfo
4774 *cache_info;
4775
4776 MagickBooleanType
4777 status;
4778
cristy3ed852e2009-09-05 21:47:34 +00004779 MagickSizeType
4780 length,
4781 number_pixels;
4782
cristy3ed852e2009-09-05 21:47:34 +00004783 cache_info=(CacheInfo *) image->cache;
4784 assert(cache_info->signature == MagickSignature);
4785 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004786 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004787 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004788 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004789 {
cristybb503372010-05-27 20:51:26 +00004790 ssize_t
cristybad067a2010-02-15 17:20:55 +00004791 x,
4792 y;
cristy3ed852e2009-09-05 21:47:34 +00004793
cristyeaedf062010-05-29 22:36:02 +00004794 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4795 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004796 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4797 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004798 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004799 ((nexus_info->region.width == cache_info->columns) ||
4800 ((nexus_info->region.width % cache_info->columns) == 0)))))
4801 {
4802 MagickOffsetType
4803 offset;
4804
4805 /*
4806 Pixels are accessed directly from memory.
4807 */
4808 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4809 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004810 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004811 offset;
4812 nexus_info->metacontent=(void *) NULL;
4813 if (cache_info->metacontent_extent != 0)
4814 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4815 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00004816 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004817 }
4818 }
4819 /*
4820 Pixels are stored in a cache region until they are synced to the cache.
4821 */
4822 number_pixels=(MagickSizeType) nexus_info->region.width*
4823 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004824 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004825 if (cache_info->metacontent_extent != 0)
4826 length+=number_pixels*cache_info->metacontent_extent;
4827 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004828 {
4829 nexus_info->length=length;
4830 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4831 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004832 {
4833 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004834 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004835 }
cristy3ed852e2009-09-05 21:47:34 +00004836 }
4837 else
4838 if (nexus_info->length != length)
4839 {
4840 RelinquishCacheNexusPixels(nexus_info);
4841 nexus_info->length=length;
4842 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4843 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004844 {
4845 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004846 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004847 }
cristy3ed852e2009-09-05 21:47:34 +00004848 }
4849 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004850 nexus_info->metacontent=(void *) NULL;
4851 if (cache_info->metacontent_extent != 0)
4852 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004853 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004854 return(nexus_info->pixels);
4855}
4856
4857/*
4858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4859% %
4860% %
4861% %
4862% 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 %
4863% %
4864% %
4865% %
4866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4867%
4868% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4869% pixel cache and returns the previous setting. A virtual pixel is any pixel
4870% access that is outside the boundaries of the image cache.
4871%
4872% The format of the SetPixelCacheVirtualMethod() method is:
4873%
cristy387430f2012-02-07 13:09:46 +00004874% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4875% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004876%
4877% A description of each parameter follows:
4878%
4879% o image: the image.
4880%
4881% o virtual_pixel_method: choose the type of virtual pixel.
4882%
cristy387430f2012-02-07 13:09:46 +00004883% o exception: return any errors or warnings in this structure.
4884%
cristy3ed852e2009-09-05 21:47:34 +00004885*/
cristy3d4cb882012-02-07 19:11:26 +00004886
4887static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4888 ExceptionInfo *exception)
4889{
4890 CacheInfo
4891 *cache_info;
4892
4893 MagickBooleanType
4894 status;
4895
4896 ssize_t
4897 y;
4898
4899 assert(image != (Image *) NULL);
4900 assert(image->signature == MagickSignature);
4901 if (image->debug != MagickFalse)
4902 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4903 assert(image->cache != (Cache) NULL);
4904 cache_info=(CacheInfo *) image->cache;
4905 assert(cache_info->signature == MagickSignature);
4906 image->matte=MagickTrue;
4907 status=MagickTrue;
4908#if defined(MAGICKCORE_OPENMP_SUPPORT)
4909 #pragma omp parallel for schedule(static,4) shared(status)
4910#endif
4911 for (y=0; y < (ssize_t) image->rows; y++)
4912 {
4913 const int
4914 id = GetOpenMPThreadId();
4915
4916 register Quantum
4917 *restrict q;
4918
4919 register ssize_t
4920 x;
4921
4922 if (status == MagickFalse)
4923 continue;
4924 q=GetAuthenticPixelCacheNexus(image,0,y,image->columns,1,
4925 cache_info->nexus_info[id],exception);
4926 if (q == (Quantum *) NULL)
4927 {
4928 status=MagickFalse;
4929 continue;
4930 }
4931 for (x=0; x < (ssize_t) image->columns; x++)
4932 {
4933 SetPixelAlpha(image,alpha,q);
4934 q+=GetPixelChannels(image);
4935 }
4936 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4937 exception);
4938 }
4939 return(status);
4940}
4941
cristy387430f2012-02-07 13:09:46 +00004942MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4943 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004944{
4945 CacheInfo
4946 *cache_info;
4947
4948 VirtualPixelMethod
4949 method;
4950
4951 assert(image != (Image *) NULL);
4952 assert(image->signature == MagickSignature);
4953 if (image->debug != MagickFalse)
4954 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4955 assert(image->cache != (Cache) NULL);
4956 cache_info=(CacheInfo *) image->cache;
4957 assert(cache_info->signature == MagickSignature);
4958 method=cache_info->virtual_pixel_method;
4959 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004960 switch (virtual_pixel_method)
4961 {
4962 case BackgroundVirtualPixelMethod:
4963 {
4964 if ((image->background_color.matte != MagickFalse) &&
4965 (image->matte == MagickFalse))
cristy3d4cb882012-02-07 19:11:26 +00004966 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004967 break;
4968 }
4969 case TransparentVirtualPixelMethod:
4970 {
4971 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00004972 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004973 break;
4974 }
4975 default:
4976 break;
4977 }
cristy3ed852e2009-09-05 21:47:34 +00004978 return(method);
4979}
4980
4981/*
4982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4983% %
4984% %
4985% %
4986+ 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 %
4987% %
4988% %
4989% %
4990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4991%
4992% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4993% in-memory or disk cache. The method returns MagickTrue if the pixel region
4994% is synced, otherwise MagickFalse.
4995%
4996% The format of the SyncAuthenticPixelCacheNexus() method is:
4997%
4998% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4999% NexusInfo *nexus_info,ExceptionInfo *exception)
5000%
5001% A description of each parameter follows:
5002%
5003% o image: the image.
5004%
5005% o nexus_info: the cache nexus to sync.
5006%
5007% o exception: return any errors or warnings in this structure.
5008%
5009*/
cristya6577ff2011-09-02 19:54:26 +00005010MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005011 NexusInfo *nexus_info,ExceptionInfo *exception)
5012{
5013 CacheInfo
5014 *cache_info;
5015
5016 MagickBooleanType
5017 status;
5018
5019 /*
5020 Transfer pixels to the cache.
5021 */
5022 assert(image != (Image *) NULL);
5023 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005024 if (image->cache == (Cache) NULL)
5025 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5026 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005027 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005028 if (cache_info->type == UndefinedCache)
5029 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005030 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005031 return(MagickTrue);
5032 assert(cache_info->signature == MagickSignature);
5033 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005034 if ((cache_info->metacontent_extent != 0) &&
5035 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005036 return(MagickFalse);
5037 return(status);
5038}
5039
5040/*
5041%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5042% %
5043% %
5044% %
5045+ S y n c A u t h e n t i c P i x e l C a c h e %
5046% %
5047% %
5048% %
5049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5050%
5051% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5052% or disk cache. The method returns MagickTrue if the pixel region is synced,
5053% otherwise MagickFalse.
5054%
5055% The format of the SyncAuthenticPixelsCache() method is:
5056%
5057% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5058% ExceptionInfo *exception)
5059%
5060% A description of each parameter follows:
5061%
5062% o image: the image.
5063%
5064% o exception: return any errors or warnings in this structure.
5065%
5066*/
5067static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5068 ExceptionInfo *exception)
5069{
5070 CacheInfo
5071 *cache_info;
5072
cristy5c9e6f22010-09-17 17:31:01 +00005073 const int
5074 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005075
cristy4c08aed2011-07-01 19:47:50 +00005076 MagickBooleanType
5077 status;
5078
cristye7cc7cf2010-09-21 13:26:47 +00005079 assert(image != (Image *) NULL);
5080 assert(image->signature == MagickSignature);
5081 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005082 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005083 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005084 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005085 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5086 exception);
5087 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005088}
5089
5090/*
5091%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5092% %
5093% %
5094% %
5095% S y n c A u t h e n t i c P i x e l s %
5096% %
5097% %
5098% %
5099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5100%
5101% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5102% The method returns MagickTrue if the pixel region is flushed, otherwise
5103% MagickFalse.
5104%
5105% The format of the SyncAuthenticPixels() method is:
5106%
5107% MagickBooleanType SyncAuthenticPixels(Image *image,
5108% ExceptionInfo *exception)
5109%
5110% A description of each parameter follows:
5111%
5112% o image: the image.
5113%
5114% o exception: return any errors or warnings in this structure.
5115%
5116*/
5117MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5118 ExceptionInfo *exception)
5119{
5120 CacheInfo
5121 *cache_info;
5122
cristy2036f5c2010-09-19 21:18:17 +00005123 const int
5124 id = GetOpenMPThreadId();
5125
cristy4c08aed2011-07-01 19:47:50 +00005126 MagickBooleanType
5127 status;
5128
cristy3ed852e2009-09-05 21:47:34 +00005129 assert(image != (Image *) NULL);
5130 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005131 assert(image->cache != (Cache) NULL);
5132 cache_info=(CacheInfo *) image->cache;
5133 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005134 if (cache_info->methods.sync_authentic_pixels_handler !=
5135 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005136 {
5137 status=cache_info->methods.sync_authentic_pixels_handler(image,
5138 exception);
5139 return(status);
5140 }
cristy2036f5c2010-09-19 21:18:17 +00005141 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005142 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5143 exception);
5144 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005145}
5146
5147/*
5148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5149% %
5150% %
5151% %
cristyd1dd6e42011-09-04 01:46:08 +00005152+ 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 +00005153% %
5154% %
5155% %
5156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5157%
5158% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5159% The method returns MagickTrue if the pixel region is flushed, otherwise
5160% MagickFalse.
5161%
5162% The format of the SyncImagePixelCache() method is:
5163%
5164% MagickBooleanType SyncImagePixelCache(Image *image,
5165% ExceptionInfo *exception)
5166%
5167% A description of each parameter follows:
5168%
5169% o image: the image.
5170%
5171% o exception: return any errors or warnings in this structure.
5172%
5173*/
cristyd1dd6e42011-09-04 01:46:08 +00005174MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005175 ExceptionInfo *exception)
5176{
5177 CacheInfo
5178 *cache_info;
5179
5180 assert(image != (Image *) NULL);
5181 assert(exception != (ExceptionInfo *) NULL);
5182 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5183 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5184}
5185
5186/*
5187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5188% %
5189% %
5190% %
cristy4c08aed2011-07-01 19:47:50 +00005191+ 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 +00005192% %
5193% %
5194% %
5195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5196%
cristy4c08aed2011-07-01 19:47:50 +00005197% WritePixelCacheMetacontent() writes the meta-content to the specified region
5198% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005199%
cristy4c08aed2011-07-01 19:47:50 +00005200% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005201%
cristy4c08aed2011-07-01 19:47:50 +00005202% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005203% NexusInfo *nexus_info,ExceptionInfo *exception)
5204%
5205% A description of each parameter follows:
5206%
5207% o cache_info: the pixel cache.
5208%
cristy4c08aed2011-07-01 19:47:50 +00005209% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005210%
5211% o exception: return any errors or warnings in this structure.
5212%
5213*/
cristy4c08aed2011-07-01 19:47:50 +00005214static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005215 NexusInfo *nexus_info,ExceptionInfo *exception)
5216{
5217 MagickOffsetType
5218 count,
5219 offset;
5220
5221 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005222 extent,
5223 length;
cristy3ed852e2009-09-05 21:47:34 +00005224
cristy4c08aed2011-07-01 19:47:50 +00005225 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005226 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005227
cristybb503372010-05-27 20:51:26 +00005228 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005229 y;
5230
cristybb503372010-05-27 20:51:26 +00005231 size_t
cristy3ed852e2009-09-05 21:47:34 +00005232 rows;
5233
cristy4c08aed2011-07-01 19:47:50 +00005234 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005235 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005236 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005237 return(MagickTrue);
5238 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5239 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005240 length=(MagickSizeType) nexus_info->region.width*
5241 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005242 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005243 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005244 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005245 switch (cache_info->type)
5246 {
5247 case MemoryCache:
5248 case MapCache:
5249 {
cristy4c08aed2011-07-01 19:47:50 +00005250 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005251 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005252
5253 /*
cristy4c08aed2011-07-01 19:47:50 +00005254 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005255 */
cristydd341db2010-03-04 19:06:38 +00005256 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005257 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005258 {
cristy48078b12010-09-23 17:11:01 +00005259 length=extent;
cristydd341db2010-03-04 19:06:38 +00005260 rows=1UL;
5261 }
cristy4c08aed2011-07-01 19:47:50 +00005262 q=(unsigned char *) cache_info->metacontent+offset*
5263 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005264 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005265 {
cristy8f036fe2010-09-18 02:02:00 +00005266 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005267 p+=nexus_info->region.width*cache_info->metacontent_extent;
5268 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005269 }
5270 break;
5271 }
5272 case DiskCache:
5273 {
5274 /*
cristy4c08aed2011-07-01 19:47:50 +00005275 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005276 */
5277 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5278 {
5279 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5280 cache_info->cache_filename);
5281 return(MagickFalse);
5282 }
cristydd341db2010-03-04 19:06:38 +00005283 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005284 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005285 {
cristy48078b12010-09-23 17:11:01 +00005286 length=extent;
cristydd341db2010-03-04 19:06:38 +00005287 rows=1UL;
5288 }
cristy48078b12010-09-23 17:11:01 +00005289 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005290 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005291 {
cristy48078b12010-09-23 17:11:01 +00005292 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005293 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005294 cache_info->metacontent_extent,length,(const unsigned char *) p);
5295 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005296 break;
cristy4c08aed2011-07-01 19:47:50 +00005297 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005298 offset+=cache_info->columns;
5299 }
cristyc11dace2012-01-24 16:39:46 +00005300 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5301 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005302 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005303 {
5304 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5305 cache_info->cache_filename);
5306 return(MagickFalse);
5307 }
5308 break;
5309 }
5310 default:
5311 break;
5312 }
5313 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005314 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005315 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005316 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005317 nexus_info->region.width,(double) nexus_info->region.height,(double)
5318 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005319 return(MagickTrue);
5320}
5321
5322/*
5323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5324% %
5325% %
5326% %
5327+ W r i t e C a c h e P i x e l s %
5328% %
5329% %
5330% %
5331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5332%
5333% WritePixelCachePixels() writes image pixels to the specified region of the
5334% pixel cache.
5335%
5336% The format of the WritePixelCachePixels() method is:
5337%
5338% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5339% NexusInfo *nexus_info,ExceptionInfo *exception)
5340%
5341% A description of each parameter follows:
5342%
5343% o cache_info: the pixel cache.
5344%
5345% o nexus_info: the cache nexus to write the pixels.
5346%
5347% o exception: return any errors or warnings in this structure.
5348%
5349*/
5350static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5351 NexusInfo *nexus_info,ExceptionInfo *exception)
5352{
5353 MagickOffsetType
5354 count,
5355 offset;
5356
5357 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005358 extent,
5359 length;
cristy3ed852e2009-09-05 21:47:34 +00005360
cristy4c08aed2011-07-01 19:47:50 +00005361 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005362 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005363
cristybb503372010-05-27 20:51:26 +00005364 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005365 y;
5366
cristybb503372010-05-27 20:51:26 +00005367 size_t
cristy3ed852e2009-09-05 21:47:34 +00005368 rows;
5369
cristy4c08aed2011-07-01 19:47:50 +00005370 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005371 return(MagickTrue);
5372 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5373 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005374 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005375 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005376 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005377 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005378 p=nexus_info->pixels;
5379 switch (cache_info->type)
5380 {
5381 case MemoryCache:
5382 case MapCache:
5383 {
cristy4c08aed2011-07-01 19:47:50 +00005384 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005385 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005386
5387 /*
5388 Write pixels to memory.
5389 */
cristydd341db2010-03-04 19:06:38 +00005390 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005391 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005392 {
cristy48078b12010-09-23 17:11:01 +00005393 length=extent;
cristydd341db2010-03-04 19:06:38 +00005394 rows=1UL;
5395 }
cristyed231572011-07-14 02:18:59 +00005396 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005397 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005398 {
cristy8f036fe2010-09-18 02:02:00 +00005399 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005400 p+=nexus_info->region.width*cache_info->number_channels;
5401 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005402 }
5403 break;
5404 }
5405 case DiskCache:
5406 {
5407 /*
5408 Write pixels to disk.
5409 */
5410 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5411 {
5412 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5413 cache_info->cache_filename);
5414 return(MagickFalse);
5415 }
cristydd341db2010-03-04 19:06:38 +00005416 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005417 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005418 {
cristy48078b12010-09-23 17:11:01 +00005419 length=extent;
cristydd341db2010-03-04 19:06:38 +00005420 rows=1UL;
5421 }
cristybb503372010-05-27 20:51:26 +00005422 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005423 {
5424 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005425 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005426 p);
5427 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005428 break;
cristyed231572011-07-14 02:18:59 +00005429 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005430 offset+=cache_info->columns;
5431 }
cristyc11dace2012-01-24 16:39:46 +00005432 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5433 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005434 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005435 {
5436 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5437 cache_info->cache_filename);
5438 return(MagickFalse);
5439 }
5440 break;
5441 }
5442 default:
5443 break;
5444 }
5445 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005446 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005447 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005448 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005449 nexus_info->region.width,(double) nexus_info->region.height,(double)
5450 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005451 return(MagickTrue);
5452}