blob: 60008442eeaa8c626bd466c47f2b6b44a5cabafb [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");
cristybb503372010-05-27 20:51:26 +0000245 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000246 {
cristy7dc8ac52012-01-10 20:14:52 +0000247 nexus_info[i]=(NexusInfo *) AcquireQuantumMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000248 if (nexus_info[i] == (NexusInfo *) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
250 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
251 nexus_info[i]->signature=MagickSignature;
252 }
253 return(nexus_info);
254}
255
256/*
257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258% %
259% %
260% %
cristyd43a46b2010-01-21 02:13:41 +0000261+ A c q u i r e P i x e l C a c h e P i x e l s %
262% %
263% %
264% %
265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266%
267% AcquirePixelCachePixels() returns the pixels associated with the specified
268% image.
269%
270% The format of the AcquirePixelCachePixels() method is:
271%
272% const void *AcquirePixelCachePixels(const Image *image,
273% MagickSizeType *length,ExceptionInfo *exception)
274%
275% A description of each parameter follows:
276%
277% o image: the image.
278%
279% o length: the pixel cache length.
280%
281% o exception: return any errors or warnings in this structure.
282%
283*/
cristyd1dd6e42011-09-04 01:46:08 +0000284MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000285 MagickSizeType *length,ExceptionInfo *exception)
286{
287 CacheInfo
288 *cache_info;
289
290 assert(image != (const Image *) NULL);
291 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000292 assert(exception != (ExceptionInfo *) NULL);
293 assert(exception->signature == MagickSignature);
294 assert(image->cache != (Cache) NULL);
295 cache_info=(CacheInfo *) image->cache;
296 assert(cache_info->signature == MagickSignature);
297 *length=0;
298 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
299 return((const void *) NULL);
300 *length=cache_info->length;
301 return((const void *) cache_info->pixels);
302}
303
304/*
305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306% %
307% %
308% %
cristyf34a1452009-10-24 22:29:27 +0000309+ C a c h e C o m p o n e n t G e n e s i s %
310% %
311% %
312% %
313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314%
315% CacheComponentGenesis() instantiates the cache component.
316%
317% The format of the CacheComponentGenesis method is:
318%
319% MagickBooleanType CacheComponentGenesis(void)
320%
321*/
cristy5ff4eaf2011-09-03 01:38:02 +0000322MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000323{
cristy165b6092009-10-26 13:52:10 +0000324 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000325 return(MagickTrue);
326}
327
328/*
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330% %
331% %
332% %
333+ C a c h e C o m p o n e n t T e r m i n u s %
334% %
335% %
336% %
337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338%
339% CacheComponentTerminus() destroys the cache component.
340%
341% The format of the CacheComponentTerminus() method is:
342%
343% CacheComponentTerminus(void)
344%
345*/
cristy5ff4eaf2011-09-03 01:38:02 +0000346MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000347{
cristy18b17442009-10-25 18:36:48 +0000348 if (cache_semaphore == (SemaphoreInfo *) NULL)
349 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000350 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000351 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000352 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000353 DestroySemaphoreInfo(&cache_semaphore);
354}
355
356/*
357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358% %
359% %
360% %
cristy3ed852e2009-09-05 21:47:34 +0000361+ C l o n e P i x e l C a c h e %
362% %
363% %
364% %
365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366%
367% ClonePixelCache() clones a pixel cache.
368%
369% The format of the ClonePixelCache() method is:
370%
371% Cache ClonePixelCache(const Cache cache)
372%
373% A description of each parameter follows:
374%
375% o cache: the pixel cache.
376%
377*/
cristya6577ff2011-09-02 19:54:26 +0000378MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000379{
380 CacheInfo
381 *clone_info;
382
383 const CacheInfo
384 *cache_info;
385
cristy9f027d12011-09-21 01:17:17 +0000386 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000387 cache_info=(const CacheInfo *) cache;
388 assert(cache_info->signature == MagickSignature);
389 if (cache_info->debug != MagickFalse)
390 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
391 cache_info->filename);
392 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
393 if (clone_info == (Cache) NULL)
394 return((Cache) NULL);
395 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
396 return((Cache ) clone_info);
397}
398
399/*
400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
401% %
402% %
403% %
cristy60c44a82009-10-07 00:58:49 +0000404+ 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 +0000405% %
406% %
407% %
408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
409% ClonePixelCachePixels() clones the source pixel cache to the destination
410% cache.
411%
412% The format of the ClonePixelCachePixels() method is:
413%
414% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
415% CacheInfo *source_info,ExceptionInfo *exception)
416%
417% A description of each parameter follows:
418%
419% o cache_info: the pixel cache.
420%
421% o source_info: the source pixel cache.
422%
423% o exception: return any errors or warnings in this structure.
424%
425*/
426
427static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
428{
429 int
430 status;
431
cristy5ee247a2010-02-12 15:42:34 +0000432 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000433 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000434 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000435 {
436 status=close(cache_info->file);
437 cache_info->file=(-1);
438 RelinquishMagickResource(FileResource,1);
439 }
cristyf84a1932010-01-03 18:00:18 +0000440 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000441 return(status == -1 ? MagickFalse : MagickTrue);
442}
443
cristy3ed852e2009-09-05 21:47:34 +0000444static inline MagickSizeType MagickMax(const MagickSizeType x,
445 const MagickSizeType y)
446{
447 if (x > y)
448 return(x);
449 return(y);
450}
451
452static inline MagickSizeType MagickMin(const MagickSizeType x,
453 const MagickSizeType y)
454{
455 if (x < y)
456 return(x);
457 return(y);
458}
459
460static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
461 const MapMode mode)
462{
463 int
464 file;
465
466 /*
467 Open pixel cache on disk.
468 */
cristyf84a1932010-01-03 18:00:18 +0000469 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000470 if (cache_info->file != -1)
471 {
cristyf84a1932010-01-03 18:00:18 +0000472 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000473 return(MagickTrue); /* cache already open */
474 }
cristy3ed852e2009-09-05 21:47:34 +0000475 if (*cache_info->cache_filename == '\0')
476 file=AcquireUniqueFileResource(cache_info->cache_filename);
477 else
478 switch (mode)
479 {
480 case ReadMode:
481 {
cristy18c6c272011-09-23 14:40:37 +0000482 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000483 break;
484 }
485 case WriteMode:
486 {
cristy18c6c272011-09-23 14:40:37 +0000487 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
488 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000489 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000490 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000491 break;
492 }
493 case IOMode:
494 default:
495 {
cristy18c6c272011-09-23 14:40:37 +0000496 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000497 O_EXCL,S_MODE);
498 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000499 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000500 break;
501 }
502 }
503 if (file == -1)
504 {
cristyf84a1932010-01-03 18:00:18 +0000505 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000506 return(MagickFalse);
507 }
508 (void) AcquireMagickResource(FileResource,1);
509 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000510 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000511 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000512 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000513 return(MagickTrue);
514}
515
516static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
517 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000518 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000519{
520 register MagickOffsetType
521 i;
522
523 ssize_t
524 count;
525
cristy08a88202010-03-04 19:18:05 +0000526 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000527#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000528 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000529 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000530 {
cristyf84a1932010-01-03 18:00:18 +0000531 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000532 return((MagickOffsetType) -1);
533 }
534#endif
535 count=0;
536 for (i=0; i < (MagickOffsetType) length; i+=count)
537 {
538#if !defined(MAGICKCORE_HAVE_PREAD)
539 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
540 (MagickSizeType) SSIZE_MAX));
541#else
542 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000543 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000544#endif
545 if (count > 0)
546 continue;
547 count=0;
548 if (errno != EINTR)
549 {
550 i=(-1);
551 break;
552 }
553 }
554#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000555 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000556#endif
557 return(i);
558}
559
560static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
561 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000562 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000563{
564 register MagickOffsetType
565 i;
566
567 ssize_t
568 count;
569
cristy08a88202010-03-04 19:18:05 +0000570 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000571#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000572 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000573 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000574 {
cristyf84a1932010-01-03 18:00:18 +0000575 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000576 return((MagickOffsetType) -1);
577 }
578#endif
579 count=0;
580 for (i=0; i < (MagickOffsetType) length; i+=count)
581 {
582#if !defined(MAGICKCORE_HAVE_PWRITE)
583 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
584 (MagickSizeType) SSIZE_MAX));
585#else
586 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000587 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000588#endif
589 if (count > 0)
590 continue;
591 count=0;
592 if (errno != EINTR)
593 {
594 i=(-1);
595 break;
596 }
597 }
598#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000599 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000600#endif
601 return(i);
602}
603
cristy4c08aed2011-07-01 19:47:50 +0000604static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000605 CacheInfo *cache_info,ExceptionInfo *exception)
606{
607 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000608 count;
cristy3ed852e2009-09-05 21:47:34 +0000609
cristy4c08aed2011-07-01 19:47:50 +0000610 register MagickOffsetType
611 i;
cristye076a6e2010-08-15 19:59:43 +0000612
cristybb503372010-05-27 20:51:26 +0000613 size_t
cristy4c08aed2011-07-01 19:47:50 +0000614 length;
cristy3ed852e2009-09-05 21:47:34 +0000615
cristy4c08aed2011-07-01 19:47:50 +0000616 unsigned char
617 *blob;
618
619 /*
620 Clone pixel cache (both caches on disk).
621 */
cristy3ed852e2009-09-05 21:47:34 +0000622 if (cache_info->debug != MagickFalse)
623 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000624 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000625 sizeof(*blob));
626 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000627 {
cristy4c08aed2011-07-01 19:47:50 +0000628 (void) ThrowMagickException(exception,GetMagickModule(),
629 ResourceLimitError,"MemoryAllocationFailed","`%s'",
630 cache_info->filename);
631 return(MagickFalse);
632 }
cristy3dedf062011-07-02 14:07:40 +0000633 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000634 {
635 blob=(unsigned char *) RelinquishMagickMemory(blob);
636 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
637 cache_info->cache_filename);
638 return(MagickFalse);
639 }
cristy3dedf062011-07-02 14:07:40 +0000640 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000641 {
642 (void) ClosePixelCacheOnDisk(cache_info);
643 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000644 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
645 clone_info->cache_filename);
646 return(MagickFalse);
647 }
cristy4c08aed2011-07-01 19:47:50 +0000648 count=0;
649 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000650 {
cristy4c08aed2011-07-01 19:47:50 +0000651 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
652 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
653 blob);
654 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000655 {
cristy4c08aed2011-07-01 19:47:50 +0000656 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
657 cache_info->cache_filename);
658 break;
cristy3ed852e2009-09-05 21:47:34 +0000659 }
cristy4c08aed2011-07-01 19:47:50 +0000660 length=(size_t) count;
661 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
662 if ((MagickSizeType) count != length)
663 {
664 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
665 clone_info->cache_filename);
666 break;
667 }
668 }
669 (void) ClosePixelCacheOnDisk(clone_info);
670 (void) ClosePixelCacheOnDisk(cache_info);
671 blob=(unsigned char *) RelinquishMagickMemory(blob);
672 if (i < (MagickOffsetType) cache_info->length)
673 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000674 return(MagickTrue);
675}
676
cristyfd24a062012-01-02 14:46:34 +0000677static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000678 CacheInfo *cache_info,ExceptionInfo *exception)
679{
680 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000681 count;
cristy3ed852e2009-09-05 21:47:34 +0000682
cristy4c08aed2011-07-01 19:47:50 +0000683 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000684 {
cristy3ed852e2009-09-05 21:47:34 +0000685 /*
cristy4c08aed2011-07-01 19:47:50 +0000686 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000687 */
cristy4c08aed2011-07-01 19:47:50 +0000688 if (cache_info->debug != MagickFalse)
689 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
690 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
691 cache_info->length);
692 return(MagickTrue);
693 }
694 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
695 {
696 /*
697 Clone pixel cache (one cache on disk, one in memory).
698 */
699 if (cache_info->debug != MagickFalse)
700 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
701 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000702 {
cristy4c08aed2011-07-01 19:47:50 +0000703 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000704 cache_info->cache_filename);
705 return(MagickFalse);
706 }
cristy4c08aed2011-07-01 19:47:50 +0000707 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
708 cache_info->length,(unsigned char *) clone_info->pixels);
709 (void) ClosePixelCacheOnDisk(cache_info);
710 if ((MagickSizeType) count != cache_info->length)
711 {
712 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
713 cache_info->cache_filename);
714 return(MagickFalse);
715 }
716 return(MagickTrue);
717 }
718 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
719 {
720 /*
721 Clone pixel cache (one cache on disk, one in memory).
722 */
723 if (clone_info->debug != MagickFalse)
724 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
725 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
726 {
727 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
728 clone_info->cache_filename);
729 return(MagickFalse);
730 }
731 count=WritePixelCacheRegion(clone_info,clone_info->offset,
732 clone_info->length,(unsigned char *) cache_info->pixels);
733 (void) ClosePixelCacheOnDisk(clone_info);
734 if ((MagickSizeType) count != clone_info->length)
735 {
736 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
737 clone_info->cache_filename);
738 return(MagickFalse);
739 }
740 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000741 }
742 /*
cristy4c08aed2011-07-01 19:47:50 +0000743 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000744 */
cristy4c08aed2011-07-01 19:47:50 +0000745 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000746}
747
cristyfd24a062012-01-02 14:46:34 +0000748static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000749 CacheInfo *cache_info,ExceptionInfo *exception)
750{
cristy4c08aed2011-07-01 19:47:50 +0000751 MagickBooleanType
752 status;
cristy3ed852e2009-09-05 21:47:34 +0000753
cristy4c08aed2011-07-01 19:47:50 +0000754 MagickOffsetType
755 cache_offset,
756 clone_offset,
757 count;
758
759 register ssize_t
760 x;
761
cristyfd24a062012-01-02 14:46:34 +0000762 register unsigned char
763 *p;
764
cristy4c08aed2011-07-01 19:47:50 +0000765 size_t
cristy3ed852e2009-09-05 21:47:34 +0000766 length;
767
cristy4c08aed2011-07-01 19:47:50 +0000768 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000769 y;
770
cristy4c08aed2011-07-01 19:47:50 +0000771 unsigned char
772 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000773
cristy4c08aed2011-07-01 19:47:50 +0000774 /*
775 Clone pixel cache (unoptimized).
776 */
cristy3ed852e2009-09-05 21:47:34 +0000777 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000778 {
cristy4c08aed2011-07-01 19:47:50 +0000779 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
780 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
781 else
782 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
783 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
784 else
785 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
787 else
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
789 }
cristyed231572011-07-14 02:18:59 +0000790 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
791 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000792 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000793 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000794 if (blob == (unsigned char *) NULL)
795 {
796 (void) ThrowMagickException(exception,GetMagickModule(),
797 ResourceLimitError,"MemoryAllocationFailed","`%s'",
798 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000799 return(MagickFalse);
800 }
cristy4c08aed2011-07-01 19:47:50 +0000801 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
802 cache_offset=0;
803 clone_offset=0;
804 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000805 {
cristy4c08aed2011-07-01 19:47:50 +0000806 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000807 {
cristy4c08aed2011-07-01 19:47:50 +0000808 blob=(unsigned char *) RelinquishMagickMemory(blob);
809 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000810 cache_info->cache_filename);
811 return(MagickFalse);
812 }
cristy4c08aed2011-07-01 19:47:50 +0000813 cache_offset=cache_info->offset;
814 }
815 if (clone_info->type == DiskCache)
816 {
cristy3dedf062011-07-02 14:07:40 +0000817 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000818 {
cristy4c08aed2011-07-01 19:47:50 +0000819 blob=(unsigned char *) RelinquishMagickMemory(blob);
820 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
821 clone_info->cache_filename);
822 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000823 }
cristy4c08aed2011-07-01 19:47:50 +0000824 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000825 }
826 /*
cristy4c08aed2011-07-01 19:47:50 +0000827 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000828 */
cristy4c08aed2011-07-01 19:47:50 +0000829 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000830 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000831 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000832 {
cristy4c08aed2011-07-01 19:47:50 +0000833 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000834 {
cristy9e0719b2011-12-29 03:45:45 +0000835 register ssize_t
836 i;
837
cristy3ed852e2009-09-05 21:47:34 +0000838 /*
cristy4c08aed2011-07-01 19:47:50 +0000839 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000840 */
cristyed231572011-07-14 02:18:59 +0000841 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000842 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000843 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000844 else
845 {
cristyfd24a062012-01-02 14:46:34 +0000846 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000847 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000848 {
cristy4c08aed2011-07-01 19:47:50 +0000849 status=MagickFalse;
850 break;
cristy3ed852e2009-09-05 21:47:34 +0000851 }
852 }
cristy4c08aed2011-07-01 19:47:50 +0000853 cache_offset+=length;
854 if ((y < (ssize_t) clone_info->rows) &&
855 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000856 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
cristy9e0719b2011-12-29 03:45:45 +0000858 PixelChannel
859 channel;
860
861 PixelTrait
862 traits;
863
864 ssize_t
865 offset;
866
cristy4c08aed2011-07-01 19:47:50 +0000867 /*
cristy3b8fe922011-12-29 18:56:23 +0000868 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000869 */
cristy9e0719b2011-12-29 03:45:45 +0000870 channel=clone_info->channel_map[i].channel;
871 traits=cache_info->channel_map[channel].traits;
872 if (traits == UndefinedPixelTrait)
873 {
cristy0f4425e2011-12-31 20:33:02 +0000874 clone_offset+=sizeof(Quantum);
875 continue;
cristy9e0719b2011-12-29 03:45:45 +0000876 }
cristy0f4425e2011-12-31 20:33:02 +0000877 offset=cache_info->channel_map[channel].offset;
878 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000879 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
880 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000881 else
882 {
cristy0f4425e2011-12-31 20:33:02 +0000883 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000884 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000885 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000886 {
cristy0f4425e2011-12-31 20:33:02 +0000887 status=MagickFalse;
888 break;
cristy4c08aed2011-07-01 19:47:50 +0000889 }
890 }
cristy9e0719b2011-12-29 03:45:45 +0000891 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000892 }
893 }
cristyed231572011-07-14 02:18:59 +0000894 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000895 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
896 for ( ; x < (ssize_t) clone_info->columns; x++)
897 {
898 /*
cristy9e0719b2011-12-29 03:45:45 +0000899 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000900 */
901 if (clone_info->type != DiskCache)
902 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
903 length);
904 else
905 {
906 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
907 if ((MagickSizeType) count != length)
908 {
909 status=MagickFalse;
910 break;
911 }
912 }
913 clone_offset+=length;
914 }
915 }
cristyed231572011-07-14 02:18:59 +0000916 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000917 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
918 for ( ; y < (ssize_t) clone_info->rows; y++)
919 {
920 /*
cristy9e0719b2011-12-29 03:45:45 +0000921 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000922 */
923 for (x=0; x < (ssize_t) clone_info->columns; x++)
924 {
925 if (clone_info->type != DiskCache)
926 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
927 length);
928 else
929 {
930 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
931 if ((MagickSizeType) count != length)
932 {
933 status=MagickFalse;
934 break;
935 }
936 }
937 clone_offset+=length;
938 }
939 }
cristy9e0719b2011-12-29 03:45:45 +0000940 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000941 (clone_info->metacontent_extent != 0))
942 {
943 /*
944 Clone metacontent.
945 */
946 for (y=0; y < (ssize_t) cache_info->rows; y++)
947 {
948 for (x=0; x < (ssize_t) cache_info->columns; x++)
949 {
950 /*
951 Read a set of metacontent.
952 */
953 length=cache_info->metacontent_extent;
954 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000955 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000956 else
957 {
cristyfd24a062012-01-02 14:46:34 +0000958 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000959 if ((MagickSizeType) count != length)
960 {
961 status=MagickFalse;
962 break;
963 }
964 }
965 cache_offset+=length;
966 if ((y < (ssize_t) clone_info->rows) &&
967 (x < (ssize_t) clone_info->columns))
968 {
969 /*
970 Write a set of metacontent.
971 */
972 length=clone_info->metacontent_extent;
973 if (clone_info->type != DiskCache)
974 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000975 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000976 else
977 {
cristyfd24a062012-01-02 14:46:34 +0000978 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000979 if ((MagickSizeType) count != length)
980 {
981 status=MagickFalse;
982 break;
983 }
984 }
985 clone_offset+=length;
986 }
987 }
988 length=clone_info->metacontent_extent;
989 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
990 for ( ; x < (ssize_t) clone_info->columns; x++)
991 {
992 /*
cristy9e0719b2011-12-29 03:45:45 +0000993 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000994 */
995 if (clone_info->type != DiskCache)
996 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
997 blob,length);
998 else
999 {
cristy208b1002011-08-07 18:51:50 +00001000 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001001 if ((MagickSizeType) count != length)
1002 {
1003 status=MagickFalse;
1004 break;
1005 }
1006 }
1007 clone_offset+=length;
1008 }
1009 }
1010 length=clone_info->metacontent_extent;
1011 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1012 for ( ; y < (ssize_t) clone_info->rows; y++)
1013 {
1014 /*
cristy9e0719b2011-12-29 03:45:45 +00001015 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001016 */
1017 for (x=0; x < (ssize_t) clone_info->columns; x++)
1018 {
1019 if (clone_info->type != DiskCache)
1020 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1021 blob,length);
1022 else
1023 {
1024 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1025 if ((MagickSizeType) count != length)
1026 {
1027 status=MagickFalse;
1028 break;
1029 }
1030 }
1031 clone_offset+=length;
1032 }
1033 }
1034 }
1035 if (clone_info->type == DiskCache)
1036 (void) ClosePixelCacheOnDisk(clone_info);
1037 if (cache_info->type == DiskCache)
1038 (void) ClosePixelCacheOnDisk(cache_info);
1039 blob=(unsigned char *) RelinquishMagickMemory(blob);
1040 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001041}
1042
1043static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1044 CacheInfo *cache_info,ExceptionInfo *exception)
1045{
cristy3dfccb22011-12-28 21:47:20 +00001046 PixelChannelMap
1047 *p,
1048 *q;
1049
cristy5a7fbfb2010-11-06 16:10:59 +00001050 if (cache_info->type == PingCache)
1051 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001052 p=cache_info->channel_map;
1053 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001054 if ((cache_info->columns == clone_info->columns) &&
1055 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001056 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001057 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001058 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001059 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1060 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001061}
1062
1063/*
1064%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1065% %
1066% %
1067% %
1068+ C l o n e P i x e l C a c h e M e t h o d s %
1069% %
1070% %
1071% %
1072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073%
1074% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1075% another.
1076%
1077% The format of the ClonePixelCacheMethods() method is:
1078%
1079% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1080%
1081% A description of each parameter follows:
1082%
1083% o clone: Specifies a pointer to a Cache structure.
1084%
1085% o cache: the pixel cache.
1086%
1087*/
cristya6577ff2011-09-02 19:54:26 +00001088MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001089{
1090 CacheInfo
1091 *cache_info,
1092 *source_info;
1093
1094 assert(clone != (Cache) NULL);
1095 source_info=(CacheInfo *) clone;
1096 assert(source_info->signature == MagickSignature);
1097 if (source_info->debug != MagickFalse)
1098 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1099 source_info->filename);
1100 assert(cache != (Cache) NULL);
1101 cache_info=(CacheInfo *) cache;
1102 assert(cache_info->signature == MagickSignature);
1103 source_info->methods=cache_info->methods;
1104}
1105
1106/*
1107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1108% %
1109% %
1110% %
1111+ D e s t r o y I m a g e P i x e l C a c h e %
1112% %
1113% %
1114% %
1115%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116%
1117% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1118%
1119% The format of the DestroyImagePixelCache() method is:
1120%
1121% void DestroyImagePixelCache(Image *image)
1122%
1123% A description of each parameter follows:
1124%
1125% o image: the image.
1126%
1127*/
1128static void DestroyImagePixelCache(Image *image)
1129{
1130 assert(image != (Image *) NULL);
1131 assert(image->signature == MagickSignature);
1132 if (image->debug != MagickFalse)
1133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1134 if (image->cache == (void *) NULL)
1135 return;
1136 image->cache=DestroyPixelCache(image->cache);
1137}
1138
1139/*
1140%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1141% %
1142% %
1143% %
1144+ D e s t r o y I m a g e P i x e l s %
1145% %
1146% %
1147% %
1148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149%
1150% DestroyImagePixels() deallocates memory associated with the pixel cache.
1151%
1152% The format of the DestroyImagePixels() method is:
1153%
1154% void DestroyImagePixels(Image *image)
1155%
1156% A description of each parameter follows:
1157%
1158% o image: the image.
1159%
1160*/
1161MagickExport void DestroyImagePixels(Image *image)
1162{
1163 CacheInfo
1164 *cache_info;
1165
1166 assert(image != (const Image *) NULL);
1167 assert(image->signature == MagickSignature);
1168 if (image->debug != MagickFalse)
1169 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1170 assert(image->cache != (Cache) NULL);
1171 cache_info=(CacheInfo *) image->cache;
1172 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001173 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1174 {
1175 cache_info->methods.destroy_pixel_handler(image);
1176 return;
1177 }
cristy2036f5c2010-09-19 21:18:17 +00001178 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001179}
1180
1181/*
1182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1183% %
1184% %
1185% %
1186+ D e s t r o y P i x e l C a c h e %
1187% %
1188% %
1189% %
1190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191%
1192% DestroyPixelCache() deallocates memory associated with the pixel cache.
1193%
1194% The format of the DestroyPixelCache() method is:
1195%
1196% Cache DestroyPixelCache(Cache cache)
1197%
1198% A description of each parameter follows:
1199%
1200% o cache: the pixel cache.
1201%
1202*/
1203
1204static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1205{
1206 switch (cache_info->type)
1207 {
1208 case MemoryCache:
1209 {
1210 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001211 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001212 cache_info->pixels);
1213 else
cristy4c08aed2011-07-01 19:47:50 +00001214 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001215 (size_t) cache_info->length);
1216 RelinquishMagickResource(MemoryResource,cache_info->length);
1217 break;
1218 }
1219 case MapCache:
1220 {
cristy4c08aed2011-07-01 19:47:50 +00001221 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001222 cache_info->length);
1223 RelinquishMagickResource(MapResource,cache_info->length);
1224 }
1225 case DiskCache:
1226 {
1227 if (cache_info->file != -1)
1228 (void) ClosePixelCacheOnDisk(cache_info);
1229 RelinquishMagickResource(DiskResource,cache_info->length);
1230 break;
1231 }
1232 default:
1233 break;
1234 }
1235 cache_info->type=UndefinedCache;
1236 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001237 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001238}
1239
cristya6577ff2011-09-02 19:54:26 +00001240MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001241{
1242 CacheInfo
1243 *cache_info;
1244
cristy3ed852e2009-09-05 21:47:34 +00001245 assert(cache != (Cache) NULL);
1246 cache_info=(CacheInfo *) cache;
1247 assert(cache_info->signature == MagickSignature);
1248 if (cache_info->debug != MagickFalse)
1249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1250 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001251 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001252 cache_info->reference_count--;
1253 if (cache_info->reference_count != 0)
1254 {
cristyf84a1932010-01-03 18:00:18 +00001255 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001256 return((Cache) NULL);
1257 }
cristyf84a1932010-01-03 18:00:18 +00001258 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001259 if (cache_info->debug != MagickFalse)
1260 {
1261 char
1262 message[MaxTextExtent];
1263
cristyb51dff52011-05-19 16:55:47 +00001264 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001265 cache_info->filename);
1266 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1267 }
cristyc2e1bdd2009-09-10 23:43:34 +00001268 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1269 (cache_info->type != DiskCache)))
1270 RelinquishPixelCachePixels(cache_info);
1271 else
1272 {
1273 RelinquishPixelCachePixels(cache_info);
1274 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1275 }
cristy3ed852e2009-09-05 21:47:34 +00001276 *cache_info->cache_filename='\0';
1277 if (cache_info->nexus_info != (NexusInfo **) NULL)
1278 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1279 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001280 if (cache_info->random_info != (RandomInfo *) NULL)
1281 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001282 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1283 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1284 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1285 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001286 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001287 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001288 cache=(Cache) NULL;
1289 return(cache);
1290}
1291
1292/*
1293%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1294% %
1295% %
1296% %
1297+ D e s t r o y P i x e l C a c h e N e x u s %
1298% %
1299% %
1300% %
1301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302%
1303% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1304%
1305% The format of the DestroyPixelCacheNexus() method is:
1306%
1307% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001308% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001309%
1310% A description of each parameter follows:
1311%
1312% o nexus_info: the nexus to destroy.
1313%
1314% o number_threads: the number of nexus threads.
1315%
1316*/
1317
1318static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1319{
1320 if (nexus_info->mapped == MagickFalse)
cristy7dc8ac52012-01-10 20:14:52 +00001321 (void) RelinquishAlignedMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001322 else
1323 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001324 nexus_info->cache=(Quantum *) NULL;
1325 nexus_info->pixels=(Quantum *) NULL;
1326 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001327 nexus_info->length=0;
1328 nexus_info->mapped=MagickFalse;
1329}
1330
cristya6577ff2011-09-02 19:54:26 +00001331MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001332 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001333{
cristybb503372010-05-27 20:51:26 +00001334 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001335 i;
1336
1337 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001338 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001339 {
cristy4c08aed2011-07-01 19:47:50 +00001340 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001341 RelinquishCacheNexusPixels(nexus_info[i]);
1342 nexus_info[i]->signature=(~MagickSignature);
cristy7dc8ac52012-01-10 20:14:52 +00001343 nexus_info[i]=(NexusInfo *) RelinquishMagickMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001344 }
cristyb41ee102010-10-04 16:46:15 +00001345 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001346 return(nexus_info);
1347}
1348
1349/*
1350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1351% %
1352% %
1353% %
cristy4c08aed2011-07-01 19:47:50 +00001354% 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 +00001355% %
1356% %
1357% %
1358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359%
cristy4c08aed2011-07-01 19:47:50 +00001360% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1361% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1362% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001363%
cristy4c08aed2011-07-01 19:47:50 +00001364% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001365%
cristy4c08aed2011-07-01 19:47:50 +00001366% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001367%
1368% A description of each parameter follows:
1369%
1370% o image: the image.
1371%
1372*/
cristy4c08aed2011-07-01 19:47:50 +00001373MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001374{
1375 CacheInfo
1376 *cache_info;
1377
cristy5c9e6f22010-09-17 17:31:01 +00001378 const int
1379 id = GetOpenMPThreadId();
1380
cristy4c08aed2011-07-01 19:47:50 +00001381 void
1382 *metacontent;
1383
cristye7cc7cf2010-09-21 13:26:47 +00001384 assert(image != (const Image *) NULL);
1385 assert(image->signature == MagickSignature);
1386 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001387 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001388 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001389 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1390 (GetAuthenticMetacontentFromHandler) NULL)
1391 {
1392 metacontent=cache_info->methods.
1393 get_authentic_metacontent_from_handler(image);
1394 return(metacontent);
1395 }
cristy6ebe97c2010-07-03 01:17:28 +00001396 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001397 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1398 cache_info->nexus_info[id]);
1399 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001400}
1401
1402/*
1403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404% %
1405% %
1406% %
cristy4c08aed2011-07-01 19:47:50 +00001407+ 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 +00001408% %
1409% %
1410% %
1411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1412%
cristy4c08aed2011-07-01 19:47:50 +00001413% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1414% with the last call to QueueAuthenticPixelsCache() or
1415% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001416%
cristy4c08aed2011-07-01 19:47:50 +00001417% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001418%
cristy4c08aed2011-07-01 19:47:50 +00001419% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001420%
1421% A description of each parameter follows:
1422%
1423% o image: the image.
1424%
1425*/
cristy4c08aed2011-07-01 19:47:50 +00001426static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001427{
1428 CacheInfo
1429 *cache_info;
1430
cristy2036f5c2010-09-19 21:18:17 +00001431 const int
1432 id = GetOpenMPThreadId();
1433
cristy4c08aed2011-07-01 19:47:50 +00001434 void
1435 *metacontent;
1436
cristy3ed852e2009-09-05 21:47:34 +00001437 assert(image != (const Image *) NULL);
1438 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001439 assert(image->cache != (Cache) NULL);
1440 cache_info=(CacheInfo *) image->cache;
1441 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001442 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001443 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1444 cache_info->nexus_info[id]);
1445 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001446}
1447
1448/*
1449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1450% %
1451% %
1452% %
1453+ 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 %
1454% %
1455% %
1456% %
1457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1458%
1459% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1460% disk pixel cache as defined by the geometry parameters. A pointer to the
1461% pixels is returned if the pixels are transferred, otherwise a NULL is
1462% returned.
1463%
1464% The format of the GetAuthenticPixelCacheNexus() method is:
1465%
cristy4c08aed2011-07-01 19:47:50 +00001466% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001467% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001468% NexusInfo *nexus_info,ExceptionInfo *exception)
1469%
1470% A description of each parameter follows:
1471%
1472% o image: the image.
1473%
1474% o x,y,columns,rows: These values define the perimeter of a region of
1475% pixels.
1476%
1477% o nexus_info: the cache nexus to return.
1478%
1479% o exception: return any errors or warnings in this structure.
1480%
1481*/
1482
cristy4c08aed2011-07-01 19:47:50 +00001483static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001484 NexusInfo *nexus_info)
1485{
cristy4c08aed2011-07-01 19:47:50 +00001486 MagickBooleanType
1487 status;
1488
cristy3ed852e2009-09-05 21:47:34 +00001489 MagickOffsetType
1490 offset;
1491
cristy73724512010-04-12 14:43:14 +00001492 if (cache_info->type == PingCache)
1493 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001494 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1495 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001496 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001497 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001498 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001499}
1500
cristya6577ff2011-09-02 19:54:26 +00001501MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001502 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001503 NexusInfo *nexus_info,ExceptionInfo *exception)
1504{
1505 CacheInfo
1506 *cache_info;
1507
cristy4c08aed2011-07-01 19:47:50 +00001508 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001509 *q;
cristy3ed852e2009-09-05 21:47:34 +00001510
1511 /*
1512 Transfer pixels from the cache.
1513 */
1514 assert(image != (Image *) NULL);
1515 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001516 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1517 exception);
cristyacd2ed22011-08-30 01:44:23 +00001518 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001519 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001520 cache_info=(CacheInfo *) image->cache;
1521 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001522 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001523 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001524 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001525 return((Quantum *) NULL);
1526 if (cache_info->metacontent_extent != 0)
1527 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1528 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001529 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001530}
1531
1532/*
1533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1534% %
1535% %
1536% %
1537+ 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 %
1538% %
1539% %
1540% %
1541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1542%
1543% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1544% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1545%
1546% The format of the GetAuthenticPixelsFromCache() method is:
1547%
cristy4c08aed2011-07-01 19:47:50 +00001548% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001549%
1550% A description of each parameter follows:
1551%
1552% o image: the image.
1553%
1554*/
cristy4c08aed2011-07-01 19:47:50 +00001555static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001556{
1557 CacheInfo
1558 *cache_info;
1559
cristy5c9e6f22010-09-17 17:31:01 +00001560 const int
1561 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001562
cristye7cc7cf2010-09-21 13:26:47 +00001563 assert(image != (const Image *) NULL);
1564 assert(image->signature == MagickSignature);
1565 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001566 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001567 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001568 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001569 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001570}
1571
1572/*
1573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1574% %
1575% %
1576% %
1577% G e t A u t h e n t i c P i x e l Q u e u e %
1578% %
1579% %
1580% %
1581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582%
cristy4c08aed2011-07-01 19:47:50 +00001583% GetAuthenticPixelQueue() returns the authentic pixels associated
1584% corresponding with the last call to QueueAuthenticPixels() or
1585% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001586%
1587% The format of the GetAuthenticPixelQueue() method is:
1588%
cristy4c08aed2011-07-01 19:47:50 +00001589% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001590%
1591% A description of each parameter follows:
1592%
1593% o image: the image.
1594%
1595*/
cristy4c08aed2011-07-01 19:47:50 +00001596MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001597{
1598 CacheInfo
1599 *cache_info;
1600
cristy2036f5c2010-09-19 21:18:17 +00001601 const int
1602 id = GetOpenMPThreadId();
1603
cristy3ed852e2009-09-05 21:47:34 +00001604 assert(image != (const Image *) NULL);
1605 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001606 assert(image->cache != (Cache) NULL);
1607 cache_info=(CacheInfo *) image->cache;
1608 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001609 if (cache_info->methods.get_authentic_pixels_from_handler !=
1610 (GetAuthenticPixelsFromHandler) NULL)
1611 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001612 assert(id < (int) cache_info->number_threads);
1613 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001614}
1615
1616/*
1617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1618% %
1619% %
1620% %
1621% G e t A u t h e n t i c P i x e l s %
1622% %
1623% %
cristy4c08aed2011-07-01 19:47:50 +00001624% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001625%
1626% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001627% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001628% representing the region is returned, otherwise NULL is returned.
1629%
1630% The returned pointer may point to a temporary working copy of the pixels
1631% or it may point to the original pixels in memory. Performance is maximized
1632% if the selected region is part of one row, or one or more full rows, since
1633% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001634% if the image is in memory, or in a memory-mapped file. The returned pointer
1635% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001636%
1637% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001638% Quantum. If the image has corresponding metacontent,call
1639% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1640% meta-content corresponding to the region. Once the Quantum array has
1641% been updated, the changes must be saved back to the underlying image using
1642% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001643%
1644% The format of the GetAuthenticPixels() method is:
1645%
cristy4c08aed2011-07-01 19:47:50 +00001646% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001647% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001648% ExceptionInfo *exception)
1649%
1650% A description of each parameter follows:
1651%
1652% o image: the image.
1653%
1654% o x,y,columns,rows: These values define the perimeter of a region of
1655% pixels.
1656%
1657% o exception: return any errors or warnings in this structure.
1658%
1659*/
cristy4c08aed2011-07-01 19:47:50 +00001660MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001661 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001662 ExceptionInfo *exception)
1663{
1664 CacheInfo
1665 *cache_info;
1666
cristy2036f5c2010-09-19 21:18:17 +00001667 const int
1668 id = GetOpenMPThreadId();
1669
cristy4c08aed2011-07-01 19:47:50 +00001670 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001671 *q;
cristy4c08aed2011-07-01 19:47:50 +00001672
cristy3ed852e2009-09-05 21:47:34 +00001673 assert(image != (Image *) NULL);
1674 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001675 assert(image->cache != (Cache) NULL);
1676 cache_info=(CacheInfo *) image->cache;
1677 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001678 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001679 (GetAuthenticPixelsHandler) NULL)
1680 {
cristyacd2ed22011-08-30 01:44:23 +00001681 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1682 exception);
1683 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001684 }
cristy2036f5c2010-09-19 21:18:17 +00001685 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001686 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001687 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001688 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001689}
1690
1691/*
1692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1693% %
1694% %
1695% %
1696+ G e t A u t h e n t i c P i x e l s C a c h e %
1697% %
1698% %
1699% %
1700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1701%
1702% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1703% as defined by the geometry parameters. A pointer to the pixels is returned
1704% if the pixels are transferred, otherwise a NULL is returned.
1705%
1706% The format of the GetAuthenticPixelsCache() method is:
1707%
cristy4c08aed2011-07-01 19:47:50 +00001708% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001709% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001710% ExceptionInfo *exception)
1711%
1712% A description of each parameter follows:
1713%
1714% o image: the image.
1715%
1716% o x,y,columns,rows: These values define the perimeter of a region of
1717% pixels.
1718%
1719% o exception: return any errors or warnings in this structure.
1720%
1721*/
cristy4c08aed2011-07-01 19:47:50 +00001722static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001723 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001724 ExceptionInfo *exception)
1725{
1726 CacheInfo
1727 *cache_info;
1728
cristy5c9e6f22010-09-17 17:31:01 +00001729 const int
1730 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001731
cristy4c08aed2011-07-01 19:47:50 +00001732 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001733 *q;
cristy4c08aed2011-07-01 19:47:50 +00001734
cristye7cc7cf2010-09-21 13:26:47 +00001735 assert(image != (const Image *) NULL);
1736 assert(image->signature == MagickSignature);
1737 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001738 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001739 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001740 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001741 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001742 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001743 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001744 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001745 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001746}
1747
1748/*
1749%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1750% %
1751% %
1752% %
1753+ G e t I m a g e E x t e n t %
1754% %
1755% %
1756% %
1757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1758%
cristy4c08aed2011-07-01 19:47:50 +00001759% GetImageExtent() returns the extent of the pixels associated corresponding
1760% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001761%
1762% The format of the GetImageExtent() method is:
1763%
1764% MagickSizeType GetImageExtent(const Image *image)
1765%
1766% A description of each parameter follows:
1767%
1768% o image: the image.
1769%
1770*/
1771MagickExport MagickSizeType GetImageExtent(const Image *image)
1772{
1773 CacheInfo
1774 *cache_info;
1775
cristy5c9e6f22010-09-17 17:31:01 +00001776 const int
1777 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001778
cristy3ed852e2009-09-05 21:47:34 +00001779 assert(image != (Image *) NULL);
1780 assert(image->signature == MagickSignature);
1781 if (image->debug != MagickFalse)
1782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1783 assert(image->cache != (Cache) NULL);
1784 cache_info=(CacheInfo *) image->cache;
1785 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001786 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001787 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001788}
1789
1790/*
1791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1792% %
1793% %
1794% %
1795+ G e t I m a g e P i x e l C a c h e %
1796% %
1797% %
1798% %
1799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1800%
1801% GetImagePixelCache() ensures that there is only a single reference to the
1802% pixel cache to be modified, updating the provided cache pointer to point to
1803% a clone of the original pixel cache if necessary.
1804%
1805% The format of the GetImagePixelCache method is:
1806%
1807% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1808% ExceptionInfo *exception)
1809%
1810% A description of each parameter follows:
1811%
1812% o image: the image.
1813%
1814% o clone: any value other than MagickFalse clones the cache pixels.
1815%
1816% o exception: return any errors or warnings in this structure.
1817%
1818*/
cristyaf894d72011-08-06 23:03:10 +00001819
cristy3ed852e2009-09-05 21:47:34 +00001820static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1821{
1822 CacheInfo
1823 *cache_info;
1824
cristy9e0719b2011-12-29 03:45:45 +00001825 PixelChannelMap
1826 *p,
1827 *q;
1828
cristy3ed852e2009-09-05 21:47:34 +00001829 /*
1830 Does the image match the pixel cache morphology?
1831 */
1832 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001833 p=image->channel_map;
1834 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001835 if ((image->storage_class != cache_info->storage_class) ||
1836 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001837 (image->matte != cache_info->matte) ||
cristy10a6c612012-01-29 21:41:05 +00001838 (image->masky != cache_info->masky) ||
cristy3ed852e2009-09-05 21:47:34 +00001839 (image->columns != cache_info->columns) ||
1840 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001841 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001842 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001843 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001844 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1845 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1846 return(MagickFalse);
1847 return(MagickTrue);
1848}
1849
cristycd01fae2011-08-06 23:52:42 +00001850static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1851 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001852{
1853 CacheInfo
1854 *cache_info;
1855
cristy3ed852e2009-09-05 21:47:34 +00001856 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001857 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001858 status;
1859
cristy50a10922010-02-15 18:35:25 +00001860 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001861 cpu_throttle = 0,
1862 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001863 time_limit = 0;
1864
cristy1ea34962010-07-01 19:49:21 +00001865 static time_t
cristy208b1002011-08-07 18:51:50 +00001866 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001867
cristyc4f9f132010-03-04 18:50:01 +00001868 status=MagickTrue;
1869 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001870 if (cpu_throttle == 0)
1871 {
1872 char
1873 *limit;
1874
1875 /*
1876 Set CPU throttle in milleseconds.
1877 */
1878 cpu_throttle=MagickResourceInfinity;
1879 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1880 if (limit == (char *) NULL)
1881 limit=GetPolicyValue("throttle");
1882 if (limit != (char *) NULL)
1883 {
1884 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1885 limit=DestroyString(limit);
1886 }
1887 }
1888 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1889 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001890 if (time_limit == 0)
1891 {
cristy6ebe97c2010-07-03 01:17:28 +00001892 /*
1893 Set the exire time in seconds.
1894 */
cristy1ea34962010-07-01 19:49:21 +00001895 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001896 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001897 }
1898 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001899 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001900 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001901 assert(image->cache != (Cache) NULL);
1902 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001903 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001904 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001905 {
cristyceb55ee2010-11-06 16:05:49 +00001906 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001907 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001908 {
cristyceb55ee2010-11-06 16:05:49 +00001909 Image
1910 clone_image;
1911
1912 CacheInfo
1913 *clone_info;
1914
1915 /*
1916 Clone pixel cache.
1917 */
1918 clone_image=(*image);
1919 clone_image.semaphore=AllocateSemaphoreInfo();
1920 clone_image.reference_count=1;
1921 clone_image.cache=ClonePixelCache(cache_info);
1922 clone_info=(CacheInfo *) clone_image.cache;
1923 status=OpenPixelCache(&clone_image,IOMode,exception);
1924 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001925 {
cristy5a7fbfb2010-11-06 16:10:59 +00001926 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001927 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001928 if (status != MagickFalse)
1929 {
cristy979bf772011-08-08 00:04:15 +00001930 if (cache_info->mode == ReadMode)
1931 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001932 destroy=MagickTrue;
1933 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001934 }
1935 }
cristyceb55ee2010-11-06 16:05:49 +00001936 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001937 }
cristyceb55ee2010-11-06 16:05:49 +00001938 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001939 }
cristy4320e0e2009-09-10 15:00:08 +00001940 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001941 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001942 if (status != MagickFalse)
1943 {
1944 /*
1945 Ensure the image matches the pixel cache morphology.
1946 */
1947 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001948 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001949 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001950 {
1951 status=OpenPixelCache(image,IOMode,exception);
1952 cache_info=(CacheInfo *) image->cache;
1953 if (cache_info->type == DiskCache)
1954 (void) ClosePixelCacheOnDisk(cache_info);
1955 }
cristy3ed852e2009-09-05 21:47:34 +00001956 }
cristyf84a1932010-01-03 18:00:18 +00001957 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001958 if (status == MagickFalse)
1959 return((Cache) NULL);
1960 return(image->cache);
1961}
1962
1963/*
1964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1965% %
1966% %
1967% %
1968% G e t O n e A u t h e n t i c P i x e l %
1969% %
1970% %
1971% %
1972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1973%
1974% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1975% location. The image background color is returned if an error occurs.
1976%
1977% The format of the GetOneAuthenticPixel() method is:
1978%
cristybb503372010-05-27 20:51:26 +00001979% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00001980% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001981%
1982% A description of each parameter follows:
1983%
1984% o image: the image.
1985%
1986% o x,y: These values define the location of the pixel to return.
1987%
1988% o pixel: return a pixel at the specified (x,y) location.
1989%
1990% o exception: return any errors or warnings in this structure.
1991%
1992*/
cristyacbbb7c2010-06-30 18:56:48 +00001993MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00001994 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001995{
1996 CacheInfo
1997 *cache_info;
1998
cristy4c08aed2011-07-01 19:47:50 +00001999 register Quantum
2000 *q;
cristy2036f5c2010-09-19 21:18:17 +00002001
cristy2ed42f62011-10-02 19:49:57 +00002002 register ssize_t
2003 i;
2004
cristy3ed852e2009-09-05 21:47:34 +00002005 assert(image != (Image *) NULL);
2006 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002007 assert(image->cache != (Cache) NULL);
2008 cache_info=(CacheInfo *) image->cache;
2009 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002010 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002011 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2012 (GetOneAuthenticPixelFromHandler) NULL)
2013 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2014 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002015 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2016 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002017 {
cristy9e0719b2011-12-29 03:45:45 +00002018 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2019 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2020 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2021 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2022 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002023 return(MagickFalse);
2024 }
2025 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2026 {
2027 PixelChannel
2028 channel;
2029
cristye2a912b2011-12-05 20:02:07 +00002030 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002031 pixel[channel]=q[i];
2032 }
cristy2036f5c2010-09-19 21:18:17 +00002033 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002034}
2035
2036/*
2037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2038% %
2039% %
2040% %
2041+ 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 %
2042% %
2043% %
2044% %
2045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2046%
2047% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2048% location. The image background color is returned if an error occurs.
2049%
2050% The format of the GetOneAuthenticPixelFromCache() method is:
2051%
2052% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002053% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002054% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002055%
2056% A description of each parameter follows:
2057%
2058% o image: the image.
2059%
2060% o x,y: These values define the location of the pixel to return.
2061%
2062% o pixel: return a pixel at the specified (x,y) location.
2063%
2064% o exception: return any errors or warnings in this structure.
2065%
2066*/
2067static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002068 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002069{
cristy098f78c2010-09-23 17:28:44 +00002070 CacheInfo
2071 *cache_info;
2072
2073 const int
2074 id = GetOpenMPThreadId();
2075
cristy4c08aed2011-07-01 19:47:50 +00002076 register Quantum
2077 *q;
cristy3ed852e2009-09-05 21:47:34 +00002078
cristy2ed42f62011-10-02 19:49:57 +00002079 register ssize_t
2080 i;
2081
cristy0158a4b2010-09-20 13:59:45 +00002082 assert(image != (const Image *) NULL);
2083 assert(image->signature == MagickSignature);
2084 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002085 cache_info=(CacheInfo *) image->cache;
2086 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002087 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002088 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002089 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2090 exception);
2091 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002092 {
cristy9e0719b2011-12-29 03:45:45 +00002093 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2094 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2095 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2096 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2097 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002098 return(MagickFalse);
2099 }
2100 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2101 {
2102 PixelChannel
2103 channel;
2104
cristye2a912b2011-12-05 20:02:07 +00002105 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002106 pixel[channel]=q[i];
2107 }
cristy3ed852e2009-09-05 21:47:34 +00002108 return(MagickTrue);
2109}
2110
2111/*
2112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2113% %
2114% %
2115% %
cristy3ed852e2009-09-05 21:47:34 +00002116% G e t O n e V i r t u a l P i x e l %
2117% %
2118% %
2119% %
2120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2121%
2122% GetOneVirtualPixel() returns a single virtual pixel at the specified
2123% (x,y) location. The image background color is returned if an error occurs.
2124% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2125%
2126% The format of the GetOneVirtualPixel() method is:
2127%
cristybb503372010-05-27 20:51:26 +00002128% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002129% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002130%
2131% A description of each parameter follows:
2132%
2133% o image: the image.
2134%
2135% o x,y: These values define the location of the pixel to return.
2136%
2137% o pixel: return a pixel at the specified (x,y) location.
2138%
2139% o exception: return any errors or warnings in this structure.
2140%
2141*/
2142MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002143 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002144{
cristy3ed852e2009-09-05 21:47:34 +00002145 CacheInfo
2146 *cache_info;
2147
cristy0158a4b2010-09-20 13:59:45 +00002148 const int
2149 id = GetOpenMPThreadId();
2150
cristy4c08aed2011-07-01 19:47:50 +00002151 const Quantum
2152 *p;
cristy2036f5c2010-09-19 21:18:17 +00002153
cristy2ed42f62011-10-02 19:49:57 +00002154 register ssize_t
2155 i;
2156
cristy3ed852e2009-09-05 21:47:34 +00002157 assert(image != (const Image *) NULL);
2158 assert(image->signature == MagickSignature);
2159 assert(image->cache != (Cache) NULL);
2160 cache_info=(CacheInfo *) image->cache;
2161 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002162 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002163 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2164 (GetOneVirtualPixelFromHandler) NULL)
2165 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2166 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002167 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002168 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002169 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002170 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002171 {
cristy9e0719b2011-12-29 03:45:45 +00002172 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2173 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2174 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2175 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2176 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002177 return(MagickFalse);
2178 }
2179 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2180 {
2181 PixelChannel
2182 channel;
2183
cristye2a912b2011-12-05 20:02:07 +00002184 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002185 pixel[channel]=p[i];
2186 }
cristy2036f5c2010-09-19 21:18:17 +00002187 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002188}
2189
2190/*
2191%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2192% %
2193% %
2194% %
2195+ 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 %
2196% %
2197% %
2198% %
2199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2200%
2201% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2202% specified (x,y) location. The image background color is returned if an
2203% error occurs.
2204%
2205% The format of the GetOneVirtualPixelFromCache() method is:
2206%
2207% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002208% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002209% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002210%
2211% A description of each parameter follows:
2212%
2213% o image: the image.
2214%
2215% o virtual_pixel_method: the virtual pixel method.
2216%
2217% o x,y: These values define the location of the pixel to return.
2218%
2219% o pixel: return a pixel at the specified (x,y) location.
2220%
2221% o exception: return any errors or warnings in this structure.
2222%
2223*/
2224static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002225 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002226 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002227{
cristy0158a4b2010-09-20 13:59:45 +00002228 CacheInfo
2229 *cache_info;
2230
2231 const int
2232 id = GetOpenMPThreadId();
2233
cristy4c08aed2011-07-01 19:47:50 +00002234 const Quantum
2235 *p;
cristy3ed852e2009-09-05 21:47:34 +00002236
cristy2ed42f62011-10-02 19:49:57 +00002237 register ssize_t
2238 i;
2239
cristye7cc7cf2010-09-21 13:26:47 +00002240 assert(image != (const Image *) NULL);
2241 assert(image->signature == MagickSignature);
2242 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002243 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002244 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002245 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002246 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002247 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002248 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002249 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002250 {
cristy9e0719b2011-12-29 03:45:45 +00002251 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2252 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2253 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2254 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2255 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002256 return(MagickFalse);
2257 }
2258 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2259 {
2260 PixelChannel
2261 channel;
2262
cristye2a912b2011-12-05 20:02:07 +00002263 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002264 pixel[channel]=p[i];
2265 }
cristy3ed852e2009-09-05 21:47:34 +00002266 return(MagickTrue);
2267}
2268
2269/*
2270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2271% %
2272% %
2273% %
cristy3aa93752011-12-18 15:54:24 +00002274% G e t O n e V i r t u a l P i x e l I n f o %
2275% %
2276% %
2277% %
2278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279%
2280% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2281% location. The image background color is returned if an error occurs. If
2282% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2283%
2284% The format of the GetOneVirtualPixelInfo() method is:
2285%
2286% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2287% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2288% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2289%
2290% A description of each parameter follows:
2291%
2292% o image: the image.
2293%
2294% o virtual_pixel_method: the virtual pixel method.
2295%
2296% o x,y: these values define the location of the pixel to return.
2297%
2298% o pixel: return a pixel at the specified (x,y) location.
2299%
2300% o exception: return any errors or warnings in this structure.
2301%
2302*/
2303MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2304 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2305 PixelInfo *pixel,ExceptionInfo *exception)
2306{
2307 CacheInfo
2308 *cache_info;
2309
2310 const int
2311 id = GetOpenMPThreadId();
2312
2313 register const Quantum
2314 *p;
2315
2316 assert(image != (const Image *) NULL);
2317 assert(image->signature == MagickSignature);
2318 assert(image->cache != (Cache) NULL);
2319 cache_info=(CacheInfo *) image->cache;
2320 assert(cache_info->signature == MagickSignature);
2321 assert(id < (int) cache_info->number_threads);
2322 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2323 cache_info->nexus_info[id],exception);
2324 GetPixelInfo(image,pixel);
2325 if (p == (const Quantum *) NULL)
2326 return(MagickFalse);
2327 GetPixelInfoPixel(image,p,pixel);
2328 return(MagickTrue);
2329}
2330
2331/*
2332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2333% %
2334% %
2335% %
cristy3ed852e2009-09-05 21:47:34 +00002336+ G e t P i x e l C a c h e C o l o r s p a c e %
2337% %
2338% %
2339% %
2340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2341%
2342% GetPixelCacheColorspace() returns the class type of the pixel cache.
2343%
2344% The format of the GetPixelCacheColorspace() method is:
2345%
2346% Colorspace GetPixelCacheColorspace(Cache cache)
2347%
2348% A description of each parameter follows:
2349%
2350% o cache: the pixel cache.
2351%
2352*/
cristya6577ff2011-09-02 19:54:26 +00002353MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002354{
2355 CacheInfo
2356 *cache_info;
2357
2358 assert(cache != (Cache) NULL);
2359 cache_info=(CacheInfo *) cache;
2360 assert(cache_info->signature == MagickSignature);
2361 if (cache_info->debug != MagickFalse)
2362 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2363 cache_info->filename);
2364 return(cache_info->colorspace);
2365}
2366
2367/*
2368%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2369% %
2370% %
2371% %
2372+ G e t P i x e l C a c h e M e t h o d s %
2373% %
2374% %
2375% %
2376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2377%
2378% GetPixelCacheMethods() initializes the CacheMethods structure.
2379%
2380% The format of the GetPixelCacheMethods() method is:
2381%
2382% void GetPixelCacheMethods(CacheMethods *cache_methods)
2383%
2384% A description of each parameter follows:
2385%
2386% o cache_methods: Specifies a pointer to a CacheMethods structure.
2387%
2388*/
cristya6577ff2011-09-02 19:54:26 +00002389MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002390{
2391 assert(cache_methods != (CacheMethods *) NULL);
2392 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2393 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2394 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002395 cache_methods->get_virtual_metacontent_from_handler=
2396 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002397 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2398 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002399 cache_methods->get_authentic_metacontent_from_handler=
2400 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002401 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2402 cache_methods->get_one_authentic_pixel_from_handler=
2403 GetOneAuthenticPixelFromCache;
2404 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2405 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2406 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2407}
2408
2409/*
2410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2411% %
2412% %
2413% %
2414+ G e t P i x e l C a c h e N e x u s E x t e n t %
2415% %
2416% %
2417% %
2418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2419%
cristy4c08aed2011-07-01 19:47:50 +00002420% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2421% corresponding with the last call to SetPixelCacheNexusPixels() or
2422% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002423%
2424% The format of the GetPixelCacheNexusExtent() method is:
2425%
2426% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2427% NexusInfo *nexus_info)
2428%
2429% A description of each parameter follows:
2430%
2431% o nexus_info: the nexus info.
2432%
2433*/
cristya6577ff2011-09-02 19:54:26 +00002434MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002435 NexusInfo *nexus_info)
2436{
2437 CacheInfo
2438 *cache_info;
2439
2440 MagickSizeType
2441 extent;
2442
cristy9f027d12011-09-21 01:17:17 +00002443 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002444 cache_info=(CacheInfo *) cache;
2445 assert(cache_info->signature == MagickSignature);
2446 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2447 if (extent == 0)
2448 return((MagickSizeType) cache_info->columns*cache_info->rows);
2449 return(extent);
2450}
2451
2452/*
2453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2454% %
2455% %
2456% %
cristy4c08aed2011-07-01 19:47:50 +00002457+ 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 +00002458% %
2459% %
2460% %
2461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462%
cristy4c08aed2011-07-01 19:47:50 +00002463% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2464% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002465%
cristy4c08aed2011-07-01 19:47:50 +00002466% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002467%
cristy4c08aed2011-07-01 19:47:50 +00002468% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002469% NexusInfo *nexus_info)
2470%
2471% A description of each parameter follows:
2472%
2473% o cache: the pixel cache.
2474%
cristy4c08aed2011-07-01 19:47:50 +00002475% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002476%
2477*/
cristya6577ff2011-09-02 19:54:26 +00002478MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002479 NexusInfo *nexus_info)
2480{
2481 CacheInfo
2482 *cache_info;
2483
cristy9f027d12011-09-21 01:17:17 +00002484 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002485 cache_info=(CacheInfo *) cache;
2486 assert(cache_info->signature == MagickSignature);
2487 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002488 return((void *) NULL);
2489 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002490}
2491
2492/*
2493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2494% %
2495% %
2496% %
2497+ G e t P i x e l C a c h e N e x u s P i x e l s %
2498% %
2499% %
2500% %
2501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2502%
2503% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2504% cache nexus.
2505%
2506% The format of the GetPixelCacheNexusPixels() method is:
2507%
cristy4c08aed2011-07-01 19:47:50 +00002508% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002509% NexusInfo *nexus_info)
2510%
2511% A description of each parameter follows:
2512%
2513% o cache: the pixel cache.
2514%
2515% o nexus_info: the cache nexus to return the pixels.
2516%
2517*/
cristya6577ff2011-09-02 19:54:26 +00002518MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002519 NexusInfo *nexus_info)
2520{
2521 CacheInfo
2522 *cache_info;
2523
cristy9f027d12011-09-21 01:17:17 +00002524 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002525 cache_info=(CacheInfo *) cache;
2526 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002527 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002528 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002529 return(nexus_info->pixels);
2530}
2531
2532/*
2533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2534% %
2535% %
2536% %
cristy056ba772010-01-02 23:33:54 +00002537+ G e t P i x e l C a c h e P i x e l s %
2538% %
2539% %
2540% %
2541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2542%
2543% GetPixelCachePixels() returns the pixels associated with the specified image.
2544%
2545% The format of the GetPixelCachePixels() method is:
2546%
cristyf84a1932010-01-03 18:00:18 +00002547% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2548% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002549%
2550% A description of each parameter follows:
2551%
2552% o image: the image.
2553%
2554% o length: the pixel cache length.
2555%
cristyf84a1932010-01-03 18:00:18 +00002556% o exception: return any errors or warnings in this structure.
2557%
cristy056ba772010-01-02 23:33:54 +00002558*/
cristyd1dd6e42011-09-04 01:46:08 +00002559MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002560 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002561{
2562 CacheInfo
2563 *cache_info;
2564
2565 assert(image != (const Image *) NULL);
2566 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002567 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002568 assert(length != (MagickSizeType *) NULL);
2569 assert(exception != (ExceptionInfo *) NULL);
2570 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002571 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002572 assert(cache_info->signature == MagickSignature);
2573 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002574 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002575 return((void *) NULL);
2576 *length=cache_info->length;
2577 return((void *) cache_info->pixels);
2578}
2579
2580/*
2581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2582% %
2583% %
2584% %
cristyb32b90a2009-09-07 21:45:48 +00002585+ 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 +00002586% %
2587% %
2588% %
2589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2590%
2591% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2592%
2593% The format of the GetPixelCacheStorageClass() method is:
2594%
2595% ClassType GetPixelCacheStorageClass(Cache cache)
2596%
2597% A description of each parameter follows:
2598%
2599% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2600%
2601% o cache: the pixel cache.
2602%
2603*/
cristya6577ff2011-09-02 19:54:26 +00002604MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002605{
2606 CacheInfo
2607 *cache_info;
2608
2609 assert(cache != (Cache) NULL);
2610 cache_info=(CacheInfo *) cache;
2611 assert(cache_info->signature == MagickSignature);
2612 if (cache_info->debug != MagickFalse)
2613 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2614 cache_info->filename);
2615 return(cache_info->storage_class);
2616}
2617
2618/*
2619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2620% %
2621% %
2622% %
cristyb32b90a2009-09-07 21:45:48 +00002623+ G e t P i x e l C a c h e T i l e S i z e %
2624% %
2625% %
2626% %
2627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2628%
2629% GetPixelCacheTileSize() returns the pixel cache tile size.
2630%
2631% The format of the GetPixelCacheTileSize() method is:
2632%
cristybb503372010-05-27 20:51:26 +00002633% void GetPixelCacheTileSize(const Image *image,size_t *width,
2634% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002635%
2636% A description of each parameter follows:
2637%
2638% o image: the image.
2639%
2640% o width: the optimize cache tile width in pixels.
2641%
2642% o height: the optimize cache tile height in pixels.
2643%
2644*/
cristya6577ff2011-09-02 19:54:26 +00002645MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002646 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002647{
cristy4c08aed2011-07-01 19:47:50 +00002648 CacheInfo
2649 *cache_info;
2650
cristyb32b90a2009-09-07 21:45:48 +00002651 assert(image != (Image *) NULL);
2652 assert(image->signature == MagickSignature);
2653 if (image->debug != MagickFalse)
2654 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002655 cache_info=(CacheInfo *) image->cache;
2656 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002657 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002658 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002659 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002660 *height=(*width);
2661}
2662
2663/*
2664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2665% %
2666% %
2667% %
2668+ G e t P i x e l C a c h e T y p e %
2669% %
2670% %
2671% %
2672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2673%
2674% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2675%
2676% The format of the GetPixelCacheType() method is:
2677%
2678% CacheType GetPixelCacheType(const Image *image)
2679%
2680% A description of each parameter follows:
2681%
2682% o image: the image.
2683%
2684*/
cristya6577ff2011-09-02 19:54:26 +00002685MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002686{
2687 CacheInfo
2688 *cache_info;
2689
2690 assert(image != (Image *) NULL);
2691 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002692 assert(image->cache != (Cache) NULL);
2693 cache_info=(CacheInfo *) image->cache;
2694 assert(cache_info->signature == MagickSignature);
2695 return(cache_info->type);
2696}
2697
2698/*
2699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2700% %
2701% %
2702% %
cristy3ed852e2009-09-05 21:47:34 +00002703+ 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 %
2704% %
2705% %
2706% %
2707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2708%
2709% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2710% pixel cache. A virtual pixel is any pixel access that is outside the
2711% boundaries of the image cache.
2712%
2713% The format of the GetPixelCacheVirtualMethod() method is:
2714%
2715% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2716%
2717% A description of each parameter follows:
2718%
2719% o image: the image.
2720%
2721*/
cristyd1dd6e42011-09-04 01:46:08 +00002722MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002723{
2724 CacheInfo
2725 *cache_info;
2726
2727 assert(image != (Image *) NULL);
2728 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002729 assert(image->cache != (Cache) NULL);
2730 cache_info=(CacheInfo *) image->cache;
2731 assert(cache_info->signature == MagickSignature);
2732 return(cache_info->virtual_pixel_method);
2733}
2734
2735/*
2736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2737% %
2738% %
2739% %
cristy4c08aed2011-07-01 19:47:50 +00002740+ 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 +00002741% %
2742% %
2743% %
2744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2745%
cristy4c08aed2011-07-01 19:47:50 +00002746% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2747% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002748%
cristy4c08aed2011-07-01 19:47:50 +00002749% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002750%
cristy4c08aed2011-07-01 19:47:50 +00002751% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002752%
2753% A description of each parameter follows:
2754%
2755% o image: the image.
2756%
2757*/
cristy4c08aed2011-07-01 19:47:50 +00002758static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002759{
2760 CacheInfo
2761 *cache_info;
2762
cristy5c9e6f22010-09-17 17:31:01 +00002763 const int
2764 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002765
cristy4c08aed2011-07-01 19:47:50 +00002766 const void
2767 *metacontent;
2768
cristye7cc7cf2010-09-21 13:26:47 +00002769 assert(image != (const Image *) NULL);
2770 assert(image->signature == MagickSignature);
2771 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002772 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002773 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002774 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002775 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2776 cache_info->nexus_info[id]);
2777 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002778}
2779
2780/*
2781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2782% %
2783% %
2784% %
cristy4c08aed2011-07-01 19:47:50 +00002785+ 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 +00002786% %
2787% %
2788% %
2789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2790%
cristy4c08aed2011-07-01 19:47:50 +00002791% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2792% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002793%
cristy4c08aed2011-07-01 19:47:50 +00002794% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002795%
cristy4c08aed2011-07-01 19:47:50 +00002796% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002797% NexusInfo *nexus_info)
2798%
2799% A description of each parameter follows:
2800%
2801% o cache: the pixel cache.
2802%
cristy4c08aed2011-07-01 19:47:50 +00002803% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002804%
2805*/
cristya6577ff2011-09-02 19:54:26 +00002806MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002807 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002808{
2809 CacheInfo
2810 *cache_info;
2811
cristye7cc7cf2010-09-21 13:26:47 +00002812 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002813 cache_info=(CacheInfo *) cache;
2814 assert(cache_info->signature == MagickSignature);
2815 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002816 return((void *) NULL);
2817 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002818}
2819
2820/*
2821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2822% %
2823% %
2824% %
cristy4c08aed2011-07-01 19:47:50 +00002825% 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 +00002826% %
2827% %
2828% %
2829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2830%
cristy4c08aed2011-07-01 19:47:50 +00002831% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2832% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2833% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002834%
cristy4c08aed2011-07-01 19:47:50 +00002835% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002836%
cristy4c08aed2011-07-01 19:47:50 +00002837% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002838%
2839% A description of each parameter follows:
2840%
2841% o image: the image.
2842%
2843*/
cristy4c08aed2011-07-01 19:47:50 +00002844MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002845{
2846 CacheInfo
2847 *cache_info;
2848
cristy2036f5c2010-09-19 21:18:17 +00002849 const int
2850 id = GetOpenMPThreadId();
2851
cristy4c08aed2011-07-01 19:47:50 +00002852 const void
2853 *metacontent;
2854
cristy3ed852e2009-09-05 21:47:34 +00002855 assert(image != (const Image *) NULL);
2856 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002857 assert(image->cache != (Cache) NULL);
2858 cache_info=(CacheInfo *) image->cache;
2859 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002860 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2861 (GetVirtualMetacontentFromHandler) NULL)
2862 {
2863 metacontent=cache_info->methods.
2864 get_virtual_metacontent_from_handler(image);
2865 return(metacontent);
2866 }
cristy2036f5c2010-09-19 21:18:17 +00002867 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002868 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2869 cache_info->nexus_info[id]);
2870 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002871}
2872
2873/*
2874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2875% %
2876% %
2877% %
2878+ 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 %
2879% %
2880% %
2881% %
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883%
2884% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2885% pixel cache as defined by the geometry parameters. A pointer to the pixels
2886% is returned if the pixels are transferred, otherwise a NULL is returned.
2887%
2888% The format of the GetVirtualPixelsFromNexus() method is:
2889%
cristy4c08aed2011-07-01 19:47:50 +00002890% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002891% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002892% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2893% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002894%
2895% A description of each parameter follows:
2896%
2897% o image: the image.
2898%
2899% o virtual_pixel_method: the virtual pixel method.
2900%
2901% o x,y,columns,rows: These values define the perimeter of a region of
2902% pixels.
2903%
2904% o nexus_info: the cache nexus to acquire.
2905%
2906% o exception: return any errors or warnings in this structure.
2907%
2908*/
2909
cristybb503372010-05-27 20:51:26 +00002910static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002911 DitherMatrix[64] =
2912 {
2913 0, 48, 12, 60, 3, 51, 15, 63,
2914 32, 16, 44, 28, 35, 19, 47, 31,
2915 8, 56, 4, 52, 11, 59, 7, 55,
2916 40, 24, 36, 20, 43, 27, 39, 23,
2917 2, 50, 14, 62, 1, 49, 13, 61,
2918 34, 18, 46, 30, 33, 17, 45, 29,
2919 10, 58, 6, 54, 9, 57, 5, 53,
2920 42, 26, 38, 22, 41, 25, 37, 21
2921 };
2922
cristybb503372010-05-27 20:51:26 +00002923static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002924{
cristybb503372010-05-27 20:51:26 +00002925 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002926 index;
2927
2928 index=x+DitherMatrix[x & 0x07]-32L;
2929 if (index < 0L)
2930 return(0L);
cristybb503372010-05-27 20:51:26 +00002931 if (index >= (ssize_t) columns)
2932 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002933 return(index);
2934}
2935
cristybb503372010-05-27 20:51:26 +00002936static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002937{
cristybb503372010-05-27 20:51:26 +00002938 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002939 index;
2940
2941 index=y+DitherMatrix[y & 0x07]-32L;
2942 if (index < 0L)
2943 return(0L);
cristybb503372010-05-27 20:51:26 +00002944 if (index >= (ssize_t) rows)
2945 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002946 return(index);
2947}
2948
cristybb503372010-05-27 20:51:26 +00002949static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002950{
2951 if (x < 0L)
2952 return(0L);
cristybb503372010-05-27 20:51:26 +00002953 if (x >= (ssize_t) columns)
2954 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002955 return(x);
2956}
2957
cristybb503372010-05-27 20:51:26 +00002958static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002959{
2960 if (y < 0L)
2961 return(0L);
cristybb503372010-05-27 20:51:26 +00002962 if (y >= (ssize_t) rows)
2963 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002964 return(y);
2965}
2966
cristybb503372010-05-27 20:51:26 +00002967static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002968{
cristybb503372010-05-27 20:51:26 +00002969 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002970}
2971
cristybb503372010-05-27 20:51:26 +00002972static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002973{
cristybb503372010-05-27 20:51:26 +00002974 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002975}
2976
cristybb503372010-05-27 20:51:26 +00002977static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2978 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002979{
2980 MagickModulo
2981 modulo;
2982
cristy6162bb42011-07-18 11:34:09 +00002983 /*
2984 Compute the remainder of dividing offset by extent. It returns not only
2985 the quotient (tile the offset falls in) but also the positive remainer
2986 within that tile such that 0 <= remainder < extent. This method is
2987 essentially a ldiv() using a floored modulo division rather than the
2988 normal default truncated modulo division.
2989 */
cristybb503372010-05-27 20:51:26 +00002990 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002991 if (offset < 0L)
2992 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00002993 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002994 return(modulo);
2995}
2996
cristya6577ff2011-09-02 19:54:26 +00002997MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002998 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2999 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003000 ExceptionInfo *exception)
3001{
3002 CacheInfo
3003 *cache_info;
3004
3005 MagickOffsetType
3006 offset;
3007
3008 MagickSizeType
3009 length,
3010 number_pixels;
3011
3012 NexusInfo
3013 **virtual_nexus;
3014
cristy4c08aed2011-07-01 19:47:50 +00003015 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003016 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003017 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003018
3019 RectangleInfo
3020 region;
3021
cristy4c08aed2011-07-01 19:47:50 +00003022 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003023 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003024
cristy4c08aed2011-07-01 19:47:50 +00003025 register const void
3026 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003027
cristy4c08aed2011-07-01 19:47:50 +00003028 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003029 *restrict q;
3030
cristybb503372010-05-27 20:51:26 +00003031 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003032 i,
3033 u;
cristy3ed852e2009-09-05 21:47:34 +00003034
cristy4c08aed2011-07-01 19:47:50 +00003035 register unsigned char
3036 *restrict s;
3037
cristy105ba3c2011-07-18 02:28:38 +00003038 ssize_t
3039 v;
3040
cristy4c08aed2011-07-01 19:47:50 +00003041 void
cristy105ba3c2011-07-18 02:28:38 +00003042 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003043
cristy3ed852e2009-09-05 21:47:34 +00003044 /*
3045 Acquire pixels.
3046 */
cristye7cc7cf2010-09-21 13:26:47 +00003047 assert(image != (const Image *) NULL);
3048 assert(image->signature == MagickSignature);
3049 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003050 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003051 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003052 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003053 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003054 region.x=x;
3055 region.y=y;
3056 region.width=columns;
3057 region.height=rows;
3058 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003059 if (pixels == (Quantum *) NULL)
3060 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003061 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003062 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3063 nexus_info->region.x;
3064 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3065 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003066 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3067 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003068 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3069 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003070 {
3071 MagickBooleanType
3072 status;
3073
3074 /*
3075 Pixel request is inside cache extents.
3076 */
cristy4c08aed2011-07-01 19:47:50 +00003077 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003078 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003079 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3080 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003081 return((const Quantum *) NULL);
3082 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003083 {
cristy4c08aed2011-07-01 19:47:50 +00003084 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003085 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003086 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003087 }
cristyacd2ed22011-08-30 01:44:23 +00003088 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003089 }
3090 /*
3091 Pixel request is outside cache extents.
3092 */
cristy4c08aed2011-07-01 19:47:50 +00003093 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003094 virtual_nexus=AcquirePixelCacheNexus(1);
3095 if (virtual_nexus == (NexusInfo **) NULL)
3096 {
cristy4c08aed2011-07-01 19:47:50 +00003097 if (virtual_nexus != (NexusInfo **) NULL)
3098 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003099 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3100 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003101 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003102 }
cristy105ba3c2011-07-18 02:28:38 +00003103 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3104 sizeof(*virtual_pixel));
3105 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003106 switch (virtual_pixel_method)
3107 {
cristy4c08aed2011-07-01 19:47:50 +00003108 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003109 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003110 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003111 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003112 case MaskVirtualPixelMethod:
3113 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003114 case EdgeVirtualPixelMethod:
3115 case CheckerTileVirtualPixelMethod:
3116 case HorizontalTileVirtualPixelMethod:
3117 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003118 {
cristy4c08aed2011-07-01 19:47:50 +00003119 if (cache_info->metacontent_extent != 0)
3120 {
cristy6162bb42011-07-18 11:34:09 +00003121 /*
3122 Acquire a metacontent buffer.
3123 */
cristya64b85d2011-09-14 01:02:31 +00003124 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003125 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003126 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003127 {
cristy4c08aed2011-07-01 19:47:50 +00003128 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3129 (void) ThrowMagickException(exception,GetMagickModule(),
3130 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3131 return((const Quantum *) NULL);
3132 }
cristy105ba3c2011-07-18 02:28:38 +00003133 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003134 cache_info->metacontent_extent);
3135 }
3136 switch (virtual_pixel_method)
3137 {
3138 case BlackVirtualPixelMethod:
3139 {
cristy30301712011-07-18 15:06:51 +00003140 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3141 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003142 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3143 break;
3144 }
3145 case GrayVirtualPixelMethod:
3146 {
cristy30301712011-07-18 15:06:51 +00003147 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003148 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3149 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003150 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3151 break;
3152 }
3153 case TransparentVirtualPixelMethod:
3154 {
cristy30301712011-07-18 15:06:51 +00003155 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3156 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003157 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3158 break;
3159 }
3160 case MaskVirtualPixelMethod:
3161 case WhiteVirtualPixelMethod:
3162 {
cristy30301712011-07-18 15:06:51 +00003163 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3164 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003165 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3166 break;
3167 }
3168 default:
3169 {
cristy9e0719b2011-12-29 03:45:45 +00003170 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3171 virtual_pixel);
3172 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3173 virtual_pixel);
3174 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3175 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003176 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003177 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3178 virtual_pixel);
3179 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3180 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003181 break;
3182 }
3183 }
cristy3ed852e2009-09-05 21:47:34 +00003184 break;
3185 }
3186 default:
cristy3ed852e2009-09-05 21:47:34 +00003187 break;
cristy3ed852e2009-09-05 21:47:34 +00003188 }
cristybb503372010-05-27 20:51:26 +00003189 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003190 {
cristybb503372010-05-27 20:51:26 +00003191 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003192 {
3193 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003194 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003195 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3196 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003197 {
3198 MagickModulo
3199 x_modulo,
3200 y_modulo;
3201
3202 /*
3203 Transfer a single pixel.
3204 */
3205 length=(MagickSizeType) 1;
3206 switch (virtual_pixel_method)
3207 {
cristy3ed852e2009-09-05 21:47:34 +00003208 default:
3209 {
3210 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003211 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003212 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003213 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003214 break;
3215 }
3216 case RandomVirtualPixelMethod:
3217 {
3218 if (cache_info->random_info == (RandomInfo *) NULL)
3219 cache_info->random_info=AcquireRandomInfo();
3220 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003221 RandomX(cache_info->random_info,cache_info->columns),
3222 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003223 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003224 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003225 break;
3226 }
3227 case DitherVirtualPixelMethod:
3228 {
3229 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003230 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003231 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003232 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003233 break;
3234 }
3235 case TileVirtualPixelMethod:
3236 {
3237 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3238 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3239 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003240 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003241 exception);
cristy4c08aed2011-07-01 19:47:50 +00003242 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003243 break;
3244 }
3245 case MirrorVirtualPixelMethod:
3246 {
3247 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3248 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003249 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003250 x_modulo.remainder-1L;
3251 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3252 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003253 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003254 y_modulo.remainder-1L;
3255 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003256 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003257 exception);
cristy4c08aed2011-07-01 19:47:50 +00003258 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003259 break;
3260 }
3261 case HorizontalTileEdgeVirtualPixelMethod:
3262 {
3263 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3264 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003265 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003266 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003267 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003268 break;
3269 }
3270 case VerticalTileEdgeVirtualPixelMethod:
3271 {
3272 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3273 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003274 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003275 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003276 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3277 break;
3278 }
3279 case BackgroundVirtualPixelMethod:
3280 case BlackVirtualPixelMethod:
3281 case GrayVirtualPixelMethod:
3282 case TransparentVirtualPixelMethod:
3283 case MaskVirtualPixelMethod:
3284 case WhiteVirtualPixelMethod:
3285 {
3286 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003287 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003288 break;
3289 }
3290 case EdgeVirtualPixelMethod:
3291 case CheckerTileVirtualPixelMethod:
3292 {
3293 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3294 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3295 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3296 {
3297 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003298 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003299 break;
3300 }
3301 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3302 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3303 exception);
3304 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3305 break;
3306 }
3307 case HorizontalTileVirtualPixelMethod:
3308 {
3309 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3310 {
3311 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003312 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003313 break;
3314 }
3315 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3316 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3317 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3318 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3319 exception);
3320 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3321 break;
3322 }
3323 case VerticalTileVirtualPixelMethod:
3324 {
3325 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3326 {
3327 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003328 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003329 break;
3330 }
3331 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3332 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3333 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3334 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3335 exception);
3336 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003337 break;
3338 }
3339 }
cristy4c08aed2011-07-01 19:47:50 +00003340 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003341 break;
cristyed231572011-07-14 02:18:59 +00003342 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003343 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003344 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003345 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003346 {
3347 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3348 s+=cache_info->metacontent_extent;
3349 }
cristy3ed852e2009-09-05 21:47:34 +00003350 continue;
3351 }
3352 /*
3353 Transfer a run of pixels.
3354 */
cristy4c08aed2011-07-01 19:47:50 +00003355 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3356 length,1UL,*virtual_nexus,exception);
3357 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003358 break;
cristy4c08aed2011-07-01 19:47:50 +00003359 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003360 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3361 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003362 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003363 {
cristy4c08aed2011-07-01 19:47:50 +00003364 (void) memcpy(s,r,(size_t) length);
3365 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003366 }
3367 }
3368 }
cristy4c08aed2011-07-01 19:47:50 +00003369 /*
3370 Free resources.
3371 */
cristy105ba3c2011-07-18 02:28:38 +00003372 if (virtual_metacontent != (void *) NULL)
3373 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003374 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3375 return(pixels);
3376}
3377
3378/*
3379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3380% %
3381% %
3382% %
3383+ G e t V i r t u a l P i x e l C a c h e %
3384% %
3385% %
3386% %
3387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3388%
3389% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3390% cache as defined by the geometry parameters. A pointer to the pixels
3391% is returned if the pixels are transferred, otherwise a NULL is returned.
3392%
3393% The format of the GetVirtualPixelCache() method is:
3394%
cristy4c08aed2011-07-01 19:47:50 +00003395% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003396% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3397% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003398% ExceptionInfo *exception)
3399%
3400% A description of each parameter follows:
3401%
3402% o image: the image.
3403%
3404% o virtual_pixel_method: the virtual pixel method.
3405%
3406% o x,y,columns,rows: These values define the perimeter of a region of
3407% pixels.
3408%
3409% o exception: return any errors or warnings in this structure.
3410%
3411*/
cristy4c08aed2011-07-01 19:47:50 +00003412static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003413 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3414 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003415{
3416 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003417 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003418
cristy5c9e6f22010-09-17 17:31:01 +00003419 const int
3420 id = GetOpenMPThreadId();
3421
cristy4c08aed2011-07-01 19:47:50 +00003422 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003423 *p;
cristy4c08aed2011-07-01 19:47:50 +00003424
cristye7cc7cf2010-09-21 13:26:47 +00003425 assert(image != (const Image *) NULL);
3426 assert(image->signature == MagickSignature);
3427 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003428 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003429 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003430 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003431 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003432 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003433 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003434}
3435
3436/*
3437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3438% %
3439% %
3440% %
3441% G e t V i r t u a l P i x e l Q u e u e %
3442% %
3443% %
3444% %
3445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3446%
cristy4c08aed2011-07-01 19:47:50 +00003447% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3448% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003449%
3450% The format of the GetVirtualPixelQueue() method is:
3451%
cristy4c08aed2011-07-01 19:47:50 +00003452% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003453%
3454% A description of each parameter follows:
3455%
3456% o image: the image.
3457%
3458*/
cristy4c08aed2011-07-01 19:47:50 +00003459MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003460{
3461 CacheInfo
3462 *cache_info;
3463
cristy2036f5c2010-09-19 21:18:17 +00003464 const int
3465 id = GetOpenMPThreadId();
3466
cristy3ed852e2009-09-05 21:47:34 +00003467 assert(image != (const Image *) NULL);
3468 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003469 assert(image->cache != (Cache) NULL);
3470 cache_info=(CacheInfo *) image->cache;
3471 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003472 if (cache_info->methods.get_virtual_pixels_handler !=
3473 (GetVirtualPixelsHandler) NULL)
3474 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003475 assert(id < (int) cache_info->number_threads);
3476 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003477}
3478
3479/*
3480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3481% %
3482% %
3483% %
3484% G e t V i r t u a l P i x e l s %
3485% %
3486% %
3487% %
3488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3489%
3490% GetVirtualPixels() returns an immutable pixel region. If the
3491% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003492% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003493% copy of the pixels or it may point to the original pixels in memory.
3494% Performance is maximized if the selected region is part of one row, or one
3495% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003496% (without a copy) if the image is in memory, or in a memory-mapped file. The
3497% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003498%
3499% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003500% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3501% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3502% access the meta-content (of type void) corresponding to the the
3503% region.
cristy3ed852e2009-09-05 21:47:34 +00003504%
3505% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3506%
3507% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3508% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3509% GetCacheViewAuthenticPixels() instead.
3510%
3511% The format of the GetVirtualPixels() method is:
3512%
cristy4c08aed2011-07-01 19:47:50 +00003513% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003514% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003515% ExceptionInfo *exception)
3516%
3517% A description of each parameter follows:
3518%
3519% o image: the image.
3520%
3521% o x,y,columns,rows: These values define the perimeter of a region of
3522% pixels.
3523%
3524% o exception: return any errors or warnings in this structure.
3525%
3526*/
cristy4c08aed2011-07-01 19:47:50 +00003527MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003528 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3529 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003530{
3531 CacheInfo
3532 *cache_info;
3533
cristy2036f5c2010-09-19 21:18:17 +00003534 const int
3535 id = GetOpenMPThreadId();
3536
cristy4c08aed2011-07-01 19:47:50 +00003537 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003538 *p;
cristy4c08aed2011-07-01 19:47:50 +00003539
cristy3ed852e2009-09-05 21:47:34 +00003540 assert(image != (const Image *) NULL);
3541 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003542 assert(image->cache != (Cache) NULL);
3543 cache_info=(CacheInfo *) image->cache;
3544 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003545 if (cache_info->methods.get_virtual_pixel_handler !=
3546 (GetVirtualPixelHandler) NULL)
3547 return(cache_info->methods.get_virtual_pixel_handler(image,
3548 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003549 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003550 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003551 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003552 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003553}
3554
3555/*
3556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3557% %
3558% %
3559% %
3560+ 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 %
3561% %
3562% %
3563% %
3564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3565%
cristy4c08aed2011-07-01 19:47:50 +00003566% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3567% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003568%
3569% The format of the GetVirtualPixelsCache() method is:
3570%
cristy4c08aed2011-07-01 19:47:50 +00003571% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003572%
3573% A description of each parameter follows:
3574%
3575% o image: the image.
3576%
3577*/
cristy4c08aed2011-07-01 19:47:50 +00003578static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003579{
3580 CacheInfo
3581 *cache_info;
3582
cristy5c9e6f22010-09-17 17:31:01 +00003583 const int
3584 id = GetOpenMPThreadId();
3585
cristye7cc7cf2010-09-21 13:26:47 +00003586 assert(image != (const Image *) NULL);
3587 assert(image->signature == MagickSignature);
3588 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003589 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003590 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003591 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003592 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003593}
3594
3595/*
3596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3597% %
3598% %
3599% %
3600+ G e t V i r t u a l P i x e l s N e x u s %
3601% %
3602% %
3603% %
3604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605%
3606% GetVirtualPixelsNexus() returns the pixels associated with the specified
3607% cache nexus.
3608%
3609% The format of the GetVirtualPixelsNexus() method is:
3610%
cristy4c08aed2011-07-01 19:47:50 +00003611% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003612% NexusInfo *nexus_info)
3613%
3614% A description of each parameter follows:
3615%
3616% o cache: the pixel cache.
3617%
3618% o nexus_info: the cache nexus to return the colormap pixels.
3619%
3620*/
cristya6577ff2011-09-02 19:54:26 +00003621MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003622 NexusInfo *nexus_info)
3623{
3624 CacheInfo
3625 *cache_info;
3626
cristye7cc7cf2010-09-21 13:26:47 +00003627 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003628 cache_info=(CacheInfo *) cache;
3629 assert(cache_info->signature == MagickSignature);
3630 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003631 return((Quantum *) NULL);
3632 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003633}
3634
3635/*
3636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3637% %
3638% %
3639% %
cristy3ed852e2009-09-05 21:47:34 +00003640+ O p e n P i x e l C a c h e %
3641% %
3642% %
3643% %
3644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3645%
3646% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3647% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003648% metacontent, and memory mapping the cache if it is disk based. The cache
3649% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003650%
3651% The format of the OpenPixelCache() method is:
3652%
3653% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3654% ExceptionInfo *exception)
3655%
3656% A description of each parameter follows:
3657%
3658% o image: the image.
3659%
3660% o mode: ReadMode, WriteMode, or IOMode.
3661%
3662% o exception: return any errors or warnings in this structure.
3663%
3664*/
3665
cristyd43a46b2010-01-21 02:13:41 +00003666static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003667{
3668 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003669 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003670 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003671 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003672 {
3673 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003674 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003675 cache_info->length);
3676 }
3677}
3678
3679static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3680{
3681 CacheInfo
3682 *cache_info;
3683
3684 MagickOffsetType
3685 count,
3686 extent,
3687 offset;
3688
3689 cache_info=(CacheInfo *) image->cache;
3690 if (image->debug != MagickFalse)
3691 {
3692 char
3693 format[MaxTextExtent],
3694 message[MaxTextExtent];
3695
cristyb9080c92009-12-01 20:13:26 +00003696 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003697 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003698 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003699 cache_info->cache_filename,cache_info->file,format);
3700 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3701 }
3702 if (length != (MagickSizeType) ((MagickOffsetType) length))
3703 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003704 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003705 if (extent < 0)
3706 return(MagickFalse);
3707 if ((MagickSizeType) extent >= length)
3708 return(MagickTrue);
3709 offset=(MagickOffsetType) length-1;
3710 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3711 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3712}
3713
3714static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3715 ExceptionInfo *exception)
3716{
cristy3ed852e2009-09-05 21:47:34 +00003717 CacheInfo
3718 *cache_info,
3719 source_info;
3720
cristyf3a6a9d2010-11-07 21:02:56 +00003721 char
3722 format[MaxTextExtent],
3723 message[MaxTextExtent];
3724
cristy4c08aed2011-07-01 19:47:50 +00003725 MagickBooleanType
3726 status;
3727
cristy3ed852e2009-09-05 21:47:34 +00003728 MagickSizeType
3729 length,
3730 number_pixels;
3731
cristy3b8fe922011-12-29 18:56:23 +00003732 PixelChannelMap
3733 *p,
3734 *q;
3735
cristy3ed852e2009-09-05 21:47:34 +00003736 size_t
cristye076a6e2010-08-15 19:59:43 +00003737 columns,
cristy3ed852e2009-09-05 21:47:34 +00003738 packet_size;
3739
cristye7cc7cf2010-09-21 13:26:47 +00003740 assert(image != (const Image *) NULL);
3741 assert(image->signature == MagickSignature);
3742 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003743 if (image->debug != MagickFalse)
3744 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3745 if ((image->columns == 0) || (image->rows == 0))
3746 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3747 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003748 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003749 source_info=(*cache_info);
3750 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003751 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003752 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003753 cache_info->storage_class=image->storage_class;
3754 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003755 cache_info->matte=image->matte;
cristy10a6c612012-01-29 21:41:05 +00003756 cache_info->masky=image->masky;
cristy3ed852e2009-09-05 21:47:34 +00003757 cache_info->rows=image->rows;
3758 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003759 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003760 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003761 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3762 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003763 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003764 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003765 if (image->ping != MagickFalse)
3766 {
cristy73724512010-04-12 14:43:14 +00003767 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003768 cache_info->pixels=(Quantum *) NULL;
3769 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003770 cache_info->length=0;
3771 return(MagickTrue);
3772 }
cristy3ed852e2009-09-05 21:47:34 +00003773 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003774 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003775 if (image->metacontent_extent != 0)
3776 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003777 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003778 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003779 if (cache_info->columns != columns)
3780 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3781 image->filename);
3782 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00003783 p=cache_info->channel_map;
3784 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00003785 if ((cache_info->type != UndefinedCache) &&
3786 (cache_info->columns <= source_info.columns) &&
3787 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00003788 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00003789 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00003790 (cache_info->metacontent_extent <= source_info.metacontent_extent))
3791 {
3792 /*
3793 Inline pixel cache clone optimization.
3794 */
3795 if ((cache_info->columns == source_info.columns) &&
3796 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00003797 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00003798 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00003799 (cache_info->metacontent_extent == source_info.metacontent_extent))
3800 return(MagickTrue);
3801 return(ClonePixelCachePixels(cache_info,&source_info,exception));
3802 }
cristy3ed852e2009-09-05 21:47:34 +00003803 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003804 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003805 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003806 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3807 {
3808 status=AcquireMagickResource(MemoryResource,cache_info->length);
3809 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3810 (cache_info->type == MemoryCache))
3811 {
cristyd43a46b2010-01-21 02:13:41 +00003812 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003813 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003814 cache_info->pixels=source_info.pixels;
3815 else
3816 {
3817 /*
3818 Create memory pixel cache.
3819 */
cristy4c08aed2011-07-01 19:47:50 +00003820 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003821 if (image->debug != MagickFalse)
3822 {
cristy32cacff2011-12-31 03:36:27 +00003823 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003824 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003825 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3826 cache_info->filename,cache_info->mapped != MagickFalse ?
3827 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003828 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003829 format);
cristy3ed852e2009-09-05 21:47:34 +00003830 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3831 message);
3832 }
cristy3ed852e2009-09-05 21:47:34 +00003833 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003834 cache_info->metacontent=(void *) NULL;
3835 if (cache_info->metacontent_extent != 0)
3836 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003837 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003838 if ((source_info.storage_class != UndefinedClass) &&
3839 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003840 {
cristy4c08aed2011-07-01 19:47:50 +00003841 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003842 exception);
3843 RelinquishPixelCachePixels(&source_info);
3844 }
cristy4c08aed2011-07-01 19:47:50 +00003845 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003846 }
3847 }
3848 RelinquishMagickResource(MemoryResource,cache_info->length);
3849 }
3850 /*
3851 Create pixel cache on disk.
3852 */
3853 status=AcquireMagickResource(DiskResource,cache_info->length);
3854 if (status == MagickFalse)
3855 {
3856 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3857 "CacheResourcesExhausted","`%s'",image->filename);
3858 return(MagickFalse);
3859 }
cristy413f1302012-01-01 17:48:27 +00003860 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3861 {
3862 (void) ClosePixelCacheOnDisk(cache_info);
3863 *cache_info->cache_filename='\0';
3864 }
cristy3ed852e2009-09-05 21:47:34 +00003865 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3866 {
3867 RelinquishMagickResource(DiskResource,cache_info->length);
3868 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3869 image->filename);
3870 return(MagickFalse);
3871 }
3872 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3873 cache_info->length);
3874 if (status == MagickFalse)
3875 {
3876 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3877 image->filename);
3878 return(MagickFalse);
3879 }
cristyed231572011-07-14 02:18:59 +00003880 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003881 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003882 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003883 cache_info->type=DiskCache;
3884 else
3885 {
3886 status=AcquireMagickResource(MapResource,cache_info->length);
3887 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3888 (cache_info->type != MemoryCache))
3889 cache_info->type=DiskCache;
3890 else
3891 {
cristy4c08aed2011-07-01 19:47:50 +00003892 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003893 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003894 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003895 {
cristy3ed852e2009-09-05 21:47:34 +00003896 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003897 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003898 }
3899 else
3900 {
3901 /*
3902 Create file-backed memory-mapped pixel cache.
3903 */
cristy4c08aed2011-07-01 19:47:50 +00003904 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003905 (void) ClosePixelCacheOnDisk(cache_info);
3906 cache_info->type=MapCache;
3907 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003908 cache_info->metacontent=(void *) NULL;
3909 if (cache_info->metacontent_extent != 0)
3910 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003911 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003912 if ((source_info.storage_class != UndefinedClass) &&
3913 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003914 {
3915 status=ClonePixelCachePixels(cache_info,&source_info,
3916 exception);
3917 RelinquishPixelCachePixels(&source_info);
3918 }
3919 if (image->debug != MagickFalse)
3920 {
cristy413f1302012-01-01 17:48:27 +00003921 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003922 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003923 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003924 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003925 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003926 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003927 format);
cristy3ed852e2009-09-05 21:47:34 +00003928 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3929 message);
3930 }
cristy4c08aed2011-07-01 19:47:50 +00003931 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003932 }
3933 }
3934 RelinquishMagickResource(MapResource,cache_info->length);
3935 }
cristy4c08aed2011-07-01 19:47:50 +00003936 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003937 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003938 {
3939 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3940 RelinquishPixelCachePixels(&source_info);
3941 }
3942 if (image->debug != MagickFalse)
3943 {
cristyb9080c92009-12-01 20:13:26 +00003944 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003945 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003946 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003947 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003948 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003949 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003950 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3951 }
cristy4c08aed2011-07-01 19:47:50 +00003952 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003953}
3954
3955/*
3956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3957% %
3958% %
3959% %
3960+ P e r s i s t P i x e l C a c h e %
3961% %
3962% %
3963% %
3964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3965%
3966% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3967% persistent pixel cache is one that resides on disk and is not destroyed
3968% when the program exits.
3969%
3970% The format of the PersistPixelCache() method is:
3971%
3972% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3973% const MagickBooleanType attach,MagickOffsetType *offset,
3974% ExceptionInfo *exception)
3975%
3976% A description of each parameter follows:
3977%
3978% o image: the image.
3979%
3980% o filename: the persistent pixel cache filename.
3981%
cristyf3a6a9d2010-11-07 21:02:56 +00003982% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003983%
cristy3ed852e2009-09-05 21:47:34 +00003984% o initialize: A value other than zero initializes the persistent pixel
3985% cache.
3986%
3987% o offset: the offset in the persistent cache to store pixels.
3988%
3989% o exception: return any errors or warnings in this structure.
3990%
3991*/
3992MagickExport MagickBooleanType PersistPixelCache(Image *image,
3993 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3994 ExceptionInfo *exception)
3995{
3996 CacheInfo
3997 *cache_info,
3998 *clone_info;
3999
4000 Image
4001 clone_image;
4002
cristy3ed852e2009-09-05 21:47:34 +00004003 MagickBooleanType
4004 status;
4005
cristye076a6e2010-08-15 19:59:43 +00004006 ssize_t
4007 page_size;
4008
cristy3ed852e2009-09-05 21:47:34 +00004009 assert(image != (Image *) NULL);
4010 assert(image->signature == MagickSignature);
4011 if (image->debug != MagickFalse)
4012 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4013 assert(image->cache != (void *) NULL);
4014 assert(filename != (const char *) NULL);
4015 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004016 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004017 cache_info=(CacheInfo *) image->cache;
4018 assert(cache_info->signature == MagickSignature);
4019 if (attach != MagickFalse)
4020 {
4021 /*
cristy01b7eb02009-09-10 23:10:14 +00004022 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004023 */
4024 if (image->debug != MagickFalse)
4025 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004026 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004027 (void) CopyMagickString(cache_info->cache_filename,filename,
4028 MaxTextExtent);
4029 cache_info->type=DiskCache;
4030 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004031 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004032 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004033 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004034 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004035 }
cristy01b7eb02009-09-10 23:10:14 +00004036 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4037 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004038 {
cristyf84a1932010-01-03 18:00:18 +00004039 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004040 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004041 (cache_info->reference_count == 1))
4042 {
4043 int
4044 status;
4045
4046 /*
cristy01b7eb02009-09-10 23:10:14 +00004047 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004048 */
cristy320684d2011-09-23 14:55:47 +00004049 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004050 if (status == 0)
4051 {
4052 (void) CopyMagickString(cache_info->cache_filename,filename,
4053 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004054 *offset+=cache_info->length+page_size-(cache_info->length %
4055 page_size);
cristyf84a1932010-01-03 18:00:18 +00004056 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004057 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004058 if (image->debug != MagickFalse)
4059 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4060 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004061 return(MagickTrue);
4062 }
4063 }
cristyf84a1932010-01-03 18:00:18 +00004064 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004065 }
4066 /*
cristy01b7eb02009-09-10 23:10:14 +00004067 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004068 */
4069 clone_image=(*image);
4070 clone_info=(CacheInfo *) clone_image.cache;
4071 image->cache=ClonePixelCache(cache_info);
4072 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4073 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4074 cache_info->type=DiskCache;
4075 cache_info->offset=(*offset);
4076 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004077 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004078 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004079 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004080 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004081 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4082 return(status);
4083}
4084
4085/*
4086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4087% %
4088% %
4089% %
cristyc11dace2012-01-24 16:39:46 +00004090+ Q u e u e A u t h e n t i c P i x e l C a c h e N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00004091% %
4092% %
4093% %
4094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4095%
cristyc11dace2012-01-24 16:39:46 +00004096% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4097% defined by the region rectangle and returns a pointer to the region. This
4098% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004099% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4100% pixels are transferred, otherwise a NULL is returned.
4101%
cristyc11dace2012-01-24 16:39:46 +00004102% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004103%
cristyc11dace2012-01-24 16:39:46 +00004104% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004105% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004106% const MagickBooleanType clone,NexusInfo *nexus_info,
4107% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004108%
4109% A description of each parameter follows:
4110%
4111% o image: the image.
4112%
4113% o x,y,columns,rows: These values define the perimeter of a region of
4114% pixels.
4115%
4116% o nexus_info: the cache nexus to set.
4117%
cristy65dbf172011-10-06 17:32:04 +00004118% o clone: clone the pixel cache.
4119%
cristy3ed852e2009-09-05 21:47:34 +00004120% o exception: return any errors or warnings in this structure.
4121%
4122*/
cristyc11dace2012-01-24 16:39:46 +00004123MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4124 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004125 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004126{
4127 CacheInfo
4128 *cache_info;
4129
4130 MagickOffsetType
4131 offset;
4132
4133 MagickSizeType
4134 number_pixels;
4135
4136 RectangleInfo
4137 region;
4138
4139 /*
4140 Validate pixel cache geometry.
4141 */
cristye7cc7cf2010-09-21 13:26:47 +00004142 assert(image != (const Image *) NULL);
4143 assert(image->signature == MagickSignature);
4144 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004145 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004146 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004147 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004148 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004149 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4150 {
4151 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4152 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004153 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004154 }
cristybb503372010-05-27 20:51:26 +00004155 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4156 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004157 {
4158 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4159 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004160 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004161 }
4162 offset=(MagickOffsetType) y*cache_info->columns+x;
4163 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004164 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004165 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4166 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4167 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004168 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004169 /*
4170 Return pixel cache.
4171 */
4172 region.x=x;
4173 region.y=y;
4174 region.width=columns;
4175 region.height=rows;
4176 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4177}
4178
4179/*
4180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4181% %
4182% %
4183% %
4184+ Q u e u e A u t h e n t i c P i x e l s C a c h e %
4185% %
4186% %
4187% %
4188%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4189%
4190% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4191% defined by the region rectangle and returns a pointer to the region. This
4192% region is subsequently transferred from the pixel cache with
4193% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4194% pixels are transferred, otherwise a NULL is returned.
4195%
4196% The format of the QueueAuthenticPixelsCache() method is:
4197%
cristy4c08aed2011-07-01 19:47:50 +00004198% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004199% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004200% ExceptionInfo *exception)
4201%
4202% A description of each parameter follows:
4203%
4204% o image: the image.
4205%
4206% o x,y,columns,rows: These values define the perimeter of a region of
4207% pixels.
4208%
4209% o exception: return any errors or warnings in this structure.
4210%
4211*/
cristy4c08aed2011-07-01 19:47:50 +00004212static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004213 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004214 ExceptionInfo *exception)
4215{
4216 CacheInfo
4217 *cache_info;
4218
cristy5c9e6f22010-09-17 17:31:01 +00004219 const int
4220 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004221
cristy4c08aed2011-07-01 19:47:50 +00004222 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004223 *q;
cristy4c08aed2011-07-01 19:47:50 +00004224
cristye7cc7cf2010-09-21 13:26:47 +00004225 assert(image != (const Image *) NULL);
4226 assert(image->signature == MagickSignature);
4227 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004228 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004229 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004230 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004231 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004232 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004233 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004234}
4235
4236/*
4237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4238% %
4239% %
4240% %
4241% Q u e u e A u t h e n t i c P i x e l s %
4242% %
4243% %
4244% %
4245%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4246%
4247% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004248% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004249% region is returned, otherwise NULL is returned. The returned pointer may
4250% point to a temporary working buffer for the pixels or it may point to the
4251% final location of the pixels in memory.
4252%
4253% Write-only access means that any existing pixel values corresponding to
4254% the region are ignored. This is useful if the initial image is being
4255% created from scratch, or if the existing pixel values are to be
4256% completely replaced without need to refer to their pre-existing values.
4257% The application is free to read and write the pixel buffer returned by
4258% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4259% initialize the pixel array values. Initializing pixel array values is the
4260% application's responsibility.
4261%
4262% Performance is maximized if the selected region is part of one row, or
4263% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004264% pixels in-place (without a copy) if the image is in memory, or in a
4265% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004266% by the user.
4267%
4268% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004269% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4270% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4271% obtain the meta-content (of type void) corresponding to the region.
4272% Once the Quantum (and/or Quantum) array has been updated, the
4273% changes must be saved back to the underlying image using
4274% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004275%
4276% The format of the QueueAuthenticPixels() method is:
4277%
cristy4c08aed2011-07-01 19:47:50 +00004278% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004279% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004280% ExceptionInfo *exception)
4281%
4282% A description of each parameter follows:
4283%
4284% o image: the image.
4285%
4286% o x,y,columns,rows: These values define the perimeter of a region of
4287% pixels.
4288%
4289% o exception: return any errors or warnings in this structure.
4290%
4291*/
cristy4c08aed2011-07-01 19:47:50 +00004292MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004293 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004294 ExceptionInfo *exception)
4295{
4296 CacheInfo
4297 *cache_info;
4298
cristy2036f5c2010-09-19 21:18:17 +00004299 const int
4300 id = GetOpenMPThreadId();
4301
cristy4c08aed2011-07-01 19:47:50 +00004302 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004303 *q;
cristy4c08aed2011-07-01 19:47:50 +00004304
cristy3ed852e2009-09-05 21:47:34 +00004305 assert(image != (Image *) NULL);
4306 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004307 assert(image->cache != (Cache) NULL);
4308 cache_info=(CacheInfo *) image->cache;
4309 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004310 if (cache_info->methods.queue_authentic_pixels_handler !=
4311 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004312 {
cristyacd2ed22011-08-30 01:44:23 +00004313 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004314 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004315 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004316 }
cristy2036f5c2010-09-19 21:18:17 +00004317 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004318 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004319 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004320 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004321}
4322
4323/*
4324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4325% %
4326% %
4327% %
cristy4c08aed2011-07-01 19:47:50 +00004328+ R e a d P i x e l C a c h e M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00004329% %
4330% %
4331% %
4332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4333%
cristy4c08aed2011-07-01 19:47:50 +00004334% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004335% the pixel cache.
4336%
cristy4c08aed2011-07-01 19:47:50 +00004337% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004338%
cristy4c08aed2011-07-01 19:47:50 +00004339% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004340% NexusInfo *nexus_info,ExceptionInfo *exception)
4341%
4342% A description of each parameter follows:
4343%
4344% o cache_info: the pixel cache.
4345%
cristy4c08aed2011-07-01 19:47:50 +00004346% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004347%
4348% o exception: return any errors or warnings in this structure.
4349%
4350*/
cristy4c08aed2011-07-01 19:47:50 +00004351static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004352 NexusInfo *nexus_info,ExceptionInfo *exception)
4353{
4354 MagickOffsetType
4355 count,
4356 offset;
4357
4358 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004359 extent,
4360 length;
cristy3ed852e2009-09-05 21:47:34 +00004361
cristybb503372010-05-27 20:51:26 +00004362 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004363 y;
4364
cristy4c08aed2011-07-01 19:47:50 +00004365 register unsigned char
4366 *restrict q;
4367
cristybb503372010-05-27 20:51:26 +00004368 size_t
cristy3ed852e2009-09-05 21:47:34 +00004369 rows;
4370
cristy4c08aed2011-07-01 19:47:50 +00004371 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004372 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004373 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004374 return(MagickTrue);
4375 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4376 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004377 length=(MagickSizeType) nexus_info->region.width*
4378 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004379 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004380 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004381 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004382 switch (cache_info->type)
4383 {
4384 case MemoryCache:
4385 case MapCache:
4386 {
cristy4c08aed2011-07-01 19:47:50 +00004387 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004388 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004389
4390 /*
cristy4c08aed2011-07-01 19:47:50 +00004391 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004392 */
cristydd341db2010-03-04 19:06:38 +00004393 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004394 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004395 {
cristy48078b12010-09-23 17:11:01 +00004396 length=extent;
cristydd341db2010-03-04 19:06:38 +00004397 rows=1UL;
4398 }
cristy4c08aed2011-07-01 19:47:50 +00004399 p=(unsigned char *) cache_info->metacontent+offset*
4400 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004401 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004402 {
cristy8f036fe2010-09-18 02:02:00 +00004403 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004404 p+=cache_info->metacontent_extent*cache_info->columns;
4405 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004406 }
4407 break;
4408 }
4409 case DiskCache:
4410 {
4411 /*
cristy4c08aed2011-07-01 19:47:50 +00004412 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004413 */
4414 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4415 {
4416 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4417 cache_info->cache_filename);
4418 return(MagickFalse);
4419 }
cristydd341db2010-03-04 19:06:38 +00004420 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004421 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004422 {
cristy48078b12010-09-23 17:11:01 +00004423 length=extent;
cristydd341db2010-03-04 19:06:38 +00004424 rows=1UL;
4425 }
cristy48078b12010-09-23 17:11:01 +00004426 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004427 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004428 {
cristy48078b12010-09-23 17:11:01 +00004429 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004430 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004431 cache_info->metacontent_extent,length,(unsigned char *) q);
4432 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004433 break;
4434 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004435 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004436 }
cristyc11dace2012-01-24 16:39:46 +00004437 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4438 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004439 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004440 {
4441 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4442 cache_info->cache_filename);
4443 return(MagickFalse);
4444 }
4445 break;
4446 }
4447 default:
4448 break;
4449 }
4450 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004451 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004452 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004453 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004454 nexus_info->region.width,(double) nexus_info->region.height,(double)
4455 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004456 return(MagickTrue);
4457}
4458
4459/*
4460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4461% %
4462% %
4463% %
4464+ R e a d P i x e l C a c h e P i x e l s %
4465% %
4466% %
4467% %
4468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4469%
4470% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4471% cache.
4472%
4473% The format of the ReadPixelCachePixels() method is:
4474%
4475% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4476% NexusInfo *nexus_info,ExceptionInfo *exception)
4477%
4478% A description of each parameter follows:
4479%
4480% o cache_info: the pixel cache.
4481%
4482% o nexus_info: the cache nexus to read the pixels.
4483%
4484% o exception: return any errors or warnings in this structure.
4485%
4486*/
4487static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4488 NexusInfo *nexus_info,ExceptionInfo *exception)
4489{
4490 MagickOffsetType
4491 count,
4492 offset;
4493
4494 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004495 extent,
4496 length;
cristy3ed852e2009-09-05 21:47:34 +00004497
cristy4c08aed2011-07-01 19:47:50 +00004498 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004499 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004500
cristye076a6e2010-08-15 19:59:43 +00004501 register ssize_t
4502 y;
4503
cristybb503372010-05-27 20:51:26 +00004504 size_t
cristy3ed852e2009-09-05 21:47:34 +00004505 rows;
4506
cristy4c08aed2011-07-01 19:47:50 +00004507 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004508 return(MagickTrue);
4509 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4510 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004511 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004512 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004513 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004514 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004515 q=nexus_info->pixels;
4516 switch (cache_info->type)
4517 {
4518 case MemoryCache:
4519 case MapCache:
4520 {
cristy4c08aed2011-07-01 19:47:50 +00004521 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004522 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004523
4524 /*
4525 Read pixels from memory.
4526 */
cristydd341db2010-03-04 19:06:38 +00004527 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004528 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004529 {
cristy48078b12010-09-23 17:11:01 +00004530 length=extent;
cristydd341db2010-03-04 19:06:38 +00004531 rows=1UL;
4532 }
cristyed231572011-07-14 02:18:59 +00004533 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004534 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004535 {
cristy8f036fe2010-09-18 02:02:00 +00004536 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004537 p+=cache_info->number_channels*cache_info->columns;
4538 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004539 }
4540 break;
4541 }
4542 case DiskCache:
4543 {
4544 /*
4545 Read pixels from disk.
4546 */
4547 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4548 {
4549 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4550 cache_info->cache_filename);
4551 return(MagickFalse);
4552 }
cristydd341db2010-03-04 19:06:38 +00004553 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004554 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004555 {
cristy48078b12010-09-23 17:11:01 +00004556 length=extent;
cristydd341db2010-03-04 19:06:38 +00004557 rows=1UL;
4558 }
cristybb503372010-05-27 20:51:26 +00004559 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004560 {
4561 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004562 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004563 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004564 break;
4565 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004566 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004567 }
cristyc11dace2012-01-24 16:39:46 +00004568 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4569 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004570 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004571 {
4572 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4573 cache_info->cache_filename);
4574 return(MagickFalse);
4575 }
4576 break;
4577 }
4578 default:
4579 break;
4580 }
4581 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004582 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004583 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004584 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004585 nexus_info->region.width,(double) nexus_info->region.height,(double)
4586 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004587 return(MagickTrue);
4588}
4589
4590/*
4591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4592% %
4593% %
4594% %
4595+ R e f e r e n c e P i x e l C a c h e %
4596% %
4597% %
4598% %
4599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4600%
4601% ReferencePixelCache() increments the reference count associated with the
4602% pixel cache returning a pointer to the cache.
4603%
4604% The format of the ReferencePixelCache method is:
4605%
4606% Cache ReferencePixelCache(Cache cache_info)
4607%
4608% A description of each parameter follows:
4609%
4610% o cache_info: the pixel cache.
4611%
4612*/
cristya6577ff2011-09-02 19:54:26 +00004613MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004614{
4615 CacheInfo
4616 *cache_info;
4617
4618 assert(cache != (Cache *) NULL);
4619 cache_info=(CacheInfo *) cache;
4620 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004621 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004622 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004623 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004624 return(cache_info);
4625}
4626
4627/*
4628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4629% %
4630% %
4631% %
4632+ S e t P i x e l C a c h e M e t h o d s %
4633% %
4634% %
4635% %
4636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4637%
4638% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4639%
4640% The format of the SetPixelCacheMethods() method is:
4641%
4642% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4643%
4644% A description of each parameter follows:
4645%
4646% o cache: the pixel cache.
4647%
4648% o cache_methods: Specifies a pointer to a CacheMethods structure.
4649%
4650*/
cristya6577ff2011-09-02 19:54:26 +00004651MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004652{
4653 CacheInfo
4654 *cache_info;
4655
4656 GetOneAuthenticPixelFromHandler
4657 get_one_authentic_pixel_from_handler;
4658
4659 GetOneVirtualPixelFromHandler
4660 get_one_virtual_pixel_from_handler;
4661
4662 /*
4663 Set cache pixel methods.
4664 */
4665 assert(cache != (Cache) NULL);
4666 assert(cache_methods != (CacheMethods *) NULL);
4667 cache_info=(CacheInfo *) cache;
4668 assert(cache_info->signature == MagickSignature);
4669 if (cache_info->debug != MagickFalse)
4670 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4671 cache_info->filename);
4672 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4673 cache_info->methods.get_virtual_pixel_handler=
4674 cache_methods->get_virtual_pixel_handler;
4675 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4676 cache_info->methods.destroy_pixel_handler=
4677 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004678 if (cache_methods->get_virtual_metacontent_from_handler !=
4679 (GetVirtualMetacontentFromHandler) NULL)
4680 cache_info->methods.get_virtual_metacontent_from_handler=
4681 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004682 if (cache_methods->get_authentic_pixels_handler !=
4683 (GetAuthenticPixelsHandler) NULL)
4684 cache_info->methods.get_authentic_pixels_handler=
4685 cache_methods->get_authentic_pixels_handler;
4686 if (cache_methods->queue_authentic_pixels_handler !=
4687 (QueueAuthenticPixelsHandler) NULL)
4688 cache_info->methods.queue_authentic_pixels_handler=
4689 cache_methods->queue_authentic_pixels_handler;
4690 if (cache_methods->sync_authentic_pixels_handler !=
4691 (SyncAuthenticPixelsHandler) NULL)
4692 cache_info->methods.sync_authentic_pixels_handler=
4693 cache_methods->sync_authentic_pixels_handler;
4694 if (cache_methods->get_authentic_pixels_from_handler !=
4695 (GetAuthenticPixelsFromHandler) NULL)
4696 cache_info->methods.get_authentic_pixels_from_handler=
4697 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004698 if (cache_methods->get_authentic_metacontent_from_handler !=
4699 (GetAuthenticMetacontentFromHandler) NULL)
4700 cache_info->methods.get_authentic_metacontent_from_handler=
4701 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004702 get_one_virtual_pixel_from_handler=
4703 cache_info->methods.get_one_virtual_pixel_from_handler;
4704 if (get_one_virtual_pixel_from_handler !=
4705 (GetOneVirtualPixelFromHandler) NULL)
4706 cache_info->methods.get_one_virtual_pixel_from_handler=
4707 cache_methods->get_one_virtual_pixel_from_handler;
4708 get_one_authentic_pixel_from_handler=
4709 cache_methods->get_one_authentic_pixel_from_handler;
4710 if (get_one_authentic_pixel_from_handler !=
4711 (GetOneAuthenticPixelFromHandler) NULL)
4712 cache_info->methods.get_one_authentic_pixel_from_handler=
4713 cache_methods->get_one_authentic_pixel_from_handler;
4714}
4715
4716/*
4717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4718% %
4719% %
4720% %
4721+ S e t P i x e l C a c h e N e x u s P i x e l s %
4722% %
4723% %
4724% %
4725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4726%
4727% SetPixelCacheNexusPixels() defines the region of the cache for the
4728% specified cache nexus.
4729%
4730% The format of the SetPixelCacheNexusPixels() method is:
4731%
cristy4c08aed2011-07-01 19:47:50 +00004732% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004733% const RectangleInfo *region,NexusInfo *nexus_info,
4734% ExceptionInfo *exception)
4735%
4736% A description of each parameter follows:
4737%
4738% o image: the image.
4739%
4740% o region: A pointer to the RectangleInfo structure that defines the
4741% region of this particular cache nexus.
4742%
4743% o nexus_info: the cache nexus to set.
4744%
4745% o exception: return any errors or warnings in this structure.
4746%
4747*/
cristyabd6e372010-09-15 19:11:26 +00004748
4749static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4750 NexusInfo *nexus_info,ExceptionInfo *exception)
4751{
4752 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4753 return(MagickFalse);
4754 nexus_info->mapped=MagickFalse;
cristy7dc8ac52012-01-10 20:14:52 +00004755 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004756 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004757 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004758 {
4759 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004760 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004761 nexus_info->length);
4762 }
cristy4c08aed2011-07-01 19:47:50 +00004763 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004764 {
4765 (void) ThrowMagickException(exception,GetMagickModule(),
4766 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4767 cache_info->filename);
4768 return(MagickFalse);
4769 }
4770 return(MagickTrue);
4771}
4772
cristy4c08aed2011-07-01 19:47:50 +00004773static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004774 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4775{
4776 CacheInfo
4777 *cache_info;
4778
4779 MagickBooleanType
4780 status;
4781
cristy3ed852e2009-09-05 21:47:34 +00004782 MagickSizeType
4783 length,
4784 number_pixels;
4785
cristy3ed852e2009-09-05 21:47:34 +00004786 cache_info=(CacheInfo *) image->cache;
4787 assert(cache_info->signature == MagickSignature);
4788 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004789 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004790 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004791 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004792 {
cristybb503372010-05-27 20:51:26 +00004793 ssize_t
cristybad067a2010-02-15 17:20:55 +00004794 x,
4795 y;
cristy3ed852e2009-09-05 21:47:34 +00004796
cristyeaedf062010-05-29 22:36:02 +00004797 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4798 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004799 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4800 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004801 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004802 ((nexus_info->region.width == cache_info->columns) ||
4803 ((nexus_info->region.width % cache_info->columns) == 0)))))
4804 {
4805 MagickOffsetType
4806 offset;
4807
4808 /*
4809 Pixels are accessed directly from memory.
4810 */
4811 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4812 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004813 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004814 offset;
4815 nexus_info->metacontent=(void *) NULL;
4816 if (cache_info->metacontent_extent != 0)
4817 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4818 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00004819 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004820 }
4821 }
4822 /*
4823 Pixels are stored in a cache region until they are synced to the cache.
4824 */
4825 number_pixels=(MagickSizeType) nexus_info->region.width*
4826 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004827 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004828 if (cache_info->metacontent_extent != 0)
4829 length+=number_pixels*cache_info->metacontent_extent;
4830 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004831 {
4832 nexus_info->length=length;
4833 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4834 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004835 {
4836 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004837 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004838 }
cristy3ed852e2009-09-05 21:47:34 +00004839 }
4840 else
4841 if (nexus_info->length != length)
4842 {
4843 RelinquishCacheNexusPixels(nexus_info);
4844 nexus_info->length=length;
4845 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4846 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004847 {
4848 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004849 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004850 }
cristy3ed852e2009-09-05 21:47:34 +00004851 }
4852 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004853 nexus_info->metacontent=(void *) NULL;
4854 if (cache_info->metacontent_extent != 0)
4855 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004856 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004857 return(nexus_info->pixels);
4858}
4859
4860/*
4861%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4862% %
4863% %
4864% %
4865% 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 %
4866% %
4867% %
4868% %
4869%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4870%
4871% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4872% pixel cache and returns the previous setting. A virtual pixel is any pixel
4873% access that is outside the boundaries of the image cache.
4874%
4875% The format of the SetPixelCacheVirtualMethod() method is:
4876%
4877% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4878% const VirtualPixelMethod virtual_pixel_method)
4879%
4880% A description of each parameter follows:
4881%
4882% o image: the image.
4883%
4884% o virtual_pixel_method: choose the type of virtual pixel.
4885%
4886*/
cristyd1dd6e42011-09-04 01:46:08 +00004887MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004888 const VirtualPixelMethod virtual_pixel_method)
4889{
4890 CacheInfo
4891 *cache_info;
4892
4893 VirtualPixelMethod
4894 method;
4895
4896 assert(image != (Image *) NULL);
4897 assert(image->signature == MagickSignature);
4898 if (image->debug != MagickFalse)
4899 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4900 assert(image->cache != (Cache) NULL);
4901 cache_info=(CacheInfo *) image->cache;
4902 assert(cache_info->signature == MagickSignature);
4903 method=cache_info->virtual_pixel_method;
4904 cache_info->virtual_pixel_method=virtual_pixel_method;
4905 return(method);
4906}
4907
4908/*
4909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4910% %
4911% %
4912% %
4913+ 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 %
4914% %
4915% %
4916% %
4917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4918%
4919% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4920% in-memory or disk cache. The method returns MagickTrue if the pixel region
4921% is synced, otherwise MagickFalse.
4922%
4923% The format of the SyncAuthenticPixelCacheNexus() method is:
4924%
4925% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4926% NexusInfo *nexus_info,ExceptionInfo *exception)
4927%
4928% A description of each parameter follows:
4929%
4930% o image: the image.
4931%
4932% o nexus_info: the cache nexus to sync.
4933%
4934% o exception: return any errors or warnings in this structure.
4935%
4936*/
cristya6577ff2011-09-02 19:54:26 +00004937MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004938 NexusInfo *nexus_info,ExceptionInfo *exception)
4939{
4940 CacheInfo
4941 *cache_info;
4942
4943 MagickBooleanType
4944 status;
4945
4946 /*
4947 Transfer pixels to the cache.
4948 */
4949 assert(image != (Image *) NULL);
4950 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004951 if (image->cache == (Cache) NULL)
4952 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4953 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004954 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004955 if (cache_info->type == UndefinedCache)
4956 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004957 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004958 return(MagickTrue);
4959 assert(cache_info->signature == MagickSignature);
4960 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00004961 if ((cache_info->metacontent_extent != 0) &&
4962 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00004963 return(MagickFalse);
4964 return(status);
4965}
4966
4967/*
4968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4969% %
4970% %
4971% %
4972+ S y n c A u t h e n t i c P i x e l C a c h e %
4973% %
4974% %
4975% %
4976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4977%
4978% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4979% or disk cache. The method returns MagickTrue if the pixel region is synced,
4980% otherwise MagickFalse.
4981%
4982% The format of the SyncAuthenticPixelsCache() method is:
4983%
4984% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4985% ExceptionInfo *exception)
4986%
4987% A description of each parameter follows:
4988%
4989% o image: the image.
4990%
4991% o exception: return any errors or warnings in this structure.
4992%
4993*/
4994static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4995 ExceptionInfo *exception)
4996{
4997 CacheInfo
4998 *cache_info;
4999
cristy5c9e6f22010-09-17 17:31:01 +00005000 const int
5001 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005002
cristy4c08aed2011-07-01 19:47:50 +00005003 MagickBooleanType
5004 status;
5005
cristye7cc7cf2010-09-21 13:26:47 +00005006 assert(image != (Image *) NULL);
5007 assert(image->signature == MagickSignature);
5008 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005009 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005010 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005011 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005012 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5013 exception);
5014 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005015}
5016
5017/*
5018%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5019% %
5020% %
5021% %
5022% S y n c A u t h e n t i c P i x e l s %
5023% %
5024% %
5025% %
5026%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5027%
5028% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5029% The method returns MagickTrue if the pixel region is flushed, otherwise
5030% MagickFalse.
5031%
5032% The format of the SyncAuthenticPixels() method is:
5033%
5034% MagickBooleanType SyncAuthenticPixels(Image *image,
5035% ExceptionInfo *exception)
5036%
5037% A description of each parameter follows:
5038%
5039% o image: the image.
5040%
5041% o exception: return any errors or warnings in this structure.
5042%
5043*/
5044MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5045 ExceptionInfo *exception)
5046{
5047 CacheInfo
5048 *cache_info;
5049
cristy2036f5c2010-09-19 21:18:17 +00005050 const int
5051 id = GetOpenMPThreadId();
5052
cristy4c08aed2011-07-01 19:47:50 +00005053 MagickBooleanType
5054 status;
5055
cristy3ed852e2009-09-05 21:47:34 +00005056 assert(image != (Image *) NULL);
5057 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005058 assert(image->cache != (Cache) NULL);
5059 cache_info=(CacheInfo *) image->cache;
5060 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005061 if (cache_info->methods.sync_authentic_pixels_handler !=
5062 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005063 {
5064 status=cache_info->methods.sync_authentic_pixels_handler(image,
5065 exception);
5066 return(status);
5067 }
cristy2036f5c2010-09-19 21:18:17 +00005068 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005069 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5070 exception);
5071 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005072}
5073
5074/*
5075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5076% %
5077% %
5078% %
cristyd1dd6e42011-09-04 01:46:08 +00005079+ 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 +00005080% %
5081% %
5082% %
5083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5084%
5085% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5086% The method returns MagickTrue if the pixel region is flushed, otherwise
5087% MagickFalse.
5088%
5089% The format of the SyncImagePixelCache() method is:
5090%
5091% MagickBooleanType SyncImagePixelCache(Image *image,
5092% ExceptionInfo *exception)
5093%
5094% A description of each parameter follows:
5095%
5096% o image: the image.
5097%
5098% o exception: return any errors or warnings in this structure.
5099%
5100*/
cristyd1dd6e42011-09-04 01:46:08 +00005101MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005102 ExceptionInfo *exception)
5103{
5104 CacheInfo
5105 *cache_info;
5106
5107 assert(image != (Image *) NULL);
5108 assert(exception != (ExceptionInfo *) NULL);
5109 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5110 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5111}
5112
5113/*
5114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5115% %
5116% %
5117% %
cristy4c08aed2011-07-01 19:47:50 +00005118+ 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 +00005119% %
5120% %
5121% %
5122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5123%
cristy4c08aed2011-07-01 19:47:50 +00005124% WritePixelCacheMetacontent() writes the meta-content to the specified region
5125% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005126%
cristy4c08aed2011-07-01 19:47:50 +00005127% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005128%
cristy4c08aed2011-07-01 19:47:50 +00005129% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005130% NexusInfo *nexus_info,ExceptionInfo *exception)
5131%
5132% A description of each parameter follows:
5133%
5134% o cache_info: the pixel cache.
5135%
cristy4c08aed2011-07-01 19:47:50 +00005136% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005137%
5138% o exception: return any errors or warnings in this structure.
5139%
5140*/
cristy4c08aed2011-07-01 19:47:50 +00005141static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005142 NexusInfo *nexus_info,ExceptionInfo *exception)
5143{
5144 MagickOffsetType
5145 count,
5146 offset;
5147
5148 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005149 extent,
5150 length;
cristy3ed852e2009-09-05 21:47:34 +00005151
cristy4c08aed2011-07-01 19:47:50 +00005152 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005153 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005154
cristybb503372010-05-27 20:51:26 +00005155 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005156 y;
5157
cristybb503372010-05-27 20:51:26 +00005158 size_t
cristy3ed852e2009-09-05 21:47:34 +00005159 rows;
5160
cristy4c08aed2011-07-01 19:47:50 +00005161 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005162 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005163 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005164 return(MagickTrue);
5165 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5166 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005167 length=(MagickSizeType) nexus_info->region.width*
5168 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005169 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005170 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005171 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005172 switch (cache_info->type)
5173 {
5174 case MemoryCache:
5175 case MapCache:
5176 {
cristy4c08aed2011-07-01 19:47:50 +00005177 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005178 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005179
5180 /*
cristy4c08aed2011-07-01 19:47:50 +00005181 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005182 */
cristydd341db2010-03-04 19:06:38 +00005183 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005184 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005185 {
cristy48078b12010-09-23 17:11:01 +00005186 length=extent;
cristydd341db2010-03-04 19:06:38 +00005187 rows=1UL;
5188 }
cristy4c08aed2011-07-01 19:47:50 +00005189 q=(unsigned char *) cache_info->metacontent+offset*
5190 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005191 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005192 {
cristy8f036fe2010-09-18 02:02:00 +00005193 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005194 p+=nexus_info->region.width*cache_info->metacontent_extent;
5195 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005196 }
5197 break;
5198 }
5199 case DiskCache:
5200 {
5201 /*
cristy4c08aed2011-07-01 19:47:50 +00005202 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005203 */
5204 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5205 {
5206 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5207 cache_info->cache_filename);
5208 return(MagickFalse);
5209 }
cristydd341db2010-03-04 19:06:38 +00005210 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005211 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005212 {
cristy48078b12010-09-23 17:11:01 +00005213 length=extent;
cristydd341db2010-03-04 19:06:38 +00005214 rows=1UL;
5215 }
cristy48078b12010-09-23 17:11:01 +00005216 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005217 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005218 {
cristy48078b12010-09-23 17:11:01 +00005219 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005220 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005221 cache_info->metacontent_extent,length,(const unsigned char *) p);
5222 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005223 break;
cristy4c08aed2011-07-01 19:47:50 +00005224 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005225 offset+=cache_info->columns;
5226 }
cristyc11dace2012-01-24 16:39:46 +00005227 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5228 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005229 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005230 {
5231 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5232 cache_info->cache_filename);
5233 return(MagickFalse);
5234 }
5235 break;
5236 }
5237 default:
5238 break;
5239 }
5240 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005241 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005242 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005243 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005244 nexus_info->region.width,(double) nexus_info->region.height,(double)
5245 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005246 return(MagickTrue);
5247}
5248
5249/*
5250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5251% %
5252% %
5253% %
5254+ W r i t e C a c h e P i x e l s %
5255% %
5256% %
5257% %
5258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5259%
5260% WritePixelCachePixels() writes image pixels to the specified region of the
5261% pixel cache.
5262%
5263% The format of the WritePixelCachePixels() method is:
5264%
5265% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5266% NexusInfo *nexus_info,ExceptionInfo *exception)
5267%
5268% A description of each parameter follows:
5269%
5270% o cache_info: the pixel cache.
5271%
5272% o nexus_info: the cache nexus to write the pixels.
5273%
5274% o exception: return any errors or warnings in this structure.
5275%
5276*/
5277static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5278 NexusInfo *nexus_info,ExceptionInfo *exception)
5279{
5280 MagickOffsetType
5281 count,
5282 offset;
5283
5284 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005285 extent,
5286 length;
cristy3ed852e2009-09-05 21:47:34 +00005287
cristy4c08aed2011-07-01 19:47:50 +00005288 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005289 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005290
cristybb503372010-05-27 20:51:26 +00005291 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005292 y;
5293
cristybb503372010-05-27 20:51:26 +00005294 size_t
cristy3ed852e2009-09-05 21:47:34 +00005295 rows;
5296
cristy4c08aed2011-07-01 19:47:50 +00005297 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005298 return(MagickTrue);
5299 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5300 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005301 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005302 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005303 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005304 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005305 p=nexus_info->pixels;
5306 switch (cache_info->type)
5307 {
5308 case MemoryCache:
5309 case MapCache:
5310 {
cristy4c08aed2011-07-01 19:47:50 +00005311 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005312 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005313
5314 /*
5315 Write pixels to memory.
5316 */
cristydd341db2010-03-04 19:06:38 +00005317 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005318 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005319 {
cristy48078b12010-09-23 17:11:01 +00005320 length=extent;
cristydd341db2010-03-04 19:06:38 +00005321 rows=1UL;
5322 }
cristyed231572011-07-14 02:18:59 +00005323 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005324 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005325 {
cristy8f036fe2010-09-18 02:02:00 +00005326 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005327 p+=nexus_info->region.width*cache_info->number_channels;
5328 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005329 }
5330 break;
5331 }
5332 case DiskCache:
5333 {
5334 /*
5335 Write pixels to disk.
5336 */
5337 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5338 {
5339 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5340 cache_info->cache_filename);
5341 return(MagickFalse);
5342 }
cristydd341db2010-03-04 19:06:38 +00005343 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005344 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005345 {
cristy48078b12010-09-23 17:11:01 +00005346 length=extent;
cristydd341db2010-03-04 19:06:38 +00005347 rows=1UL;
5348 }
cristybb503372010-05-27 20:51:26 +00005349 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005350 {
5351 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005352 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005353 p);
5354 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005355 break;
cristyed231572011-07-14 02:18:59 +00005356 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005357 offset+=cache_info->columns;
5358 }
cristyc11dace2012-01-24 16:39:46 +00005359 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5360 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005361 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005362 {
5363 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5364 cache_info->cache_filename);
5365 return(MagickFalse);
5366 }
5367 break;
5368 }
5369 default:
5370 break;
5371 }
5372 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005373 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005374 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005375 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005376 nexus_info->region.width,(double) nexus_info->region.height,(double)
5377 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005378 return(MagickTrue);
5379}