blob: 4b4ff9a9118b1a18b948213bc5b1a3b7351668a9 [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) ||
cristy183a5c72012-01-30 01:40:35 +00001838 (image->mask != cache_info->mask) ||
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);
cristy6cff7ae2012-02-07 02:26:02 +00003176 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3177 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003178 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3179 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003180 break;
3181 }
3182 }
cristy3ed852e2009-09-05 21:47:34 +00003183 break;
3184 }
3185 default:
cristy3ed852e2009-09-05 21:47:34 +00003186 break;
cristy3ed852e2009-09-05 21:47:34 +00003187 }
cristybb503372010-05-27 20:51:26 +00003188 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003189 {
cristybb503372010-05-27 20:51:26 +00003190 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003191 {
3192 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003193 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003194 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3195 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003196 {
3197 MagickModulo
3198 x_modulo,
3199 y_modulo;
3200
3201 /*
3202 Transfer a single pixel.
3203 */
3204 length=(MagickSizeType) 1;
3205 switch (virtual_pixel_method)
3206 {
cristy3ed852e2009-09-05 21:47:34 +00003207 default:
3208 {
3209 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003210 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003211 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003212 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003213 break;
3214 }
3215 case RandomVirtualPixelMethod:
3216 {
3217 if (cache_info->random_info == (RandomInfo *) NULL)
3218 cache_info->random_info=AcquireRandomInfo();
3219 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003220 RandomX(cache_info->random_info,cache_info->columns),
3221 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003222 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003223 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003224 break;
3225 }
3226 case DitherVirtualPixelMethod:
3227 {
3228 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003229 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003230 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003231 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003232 break;
3233 }
3234 case TileVirtualPixelMethod:
3235 {
3236 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3237 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3238 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003239 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003240 exception);
cristy4c08aed2011-07-01 19:47:50 +00003241 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003242 break;
3243 }
3244 case MirrorVirtualPixelMethod:
3245 {
3246 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3247 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003248 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003249 x_modulo.remainder-1L;
3250 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3251 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003252 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003253 y_modulo.remainder-1L;
3254 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003255 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003256 exception);
cristy4c08aed2011-07-01 19:47:50 +00003257 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003258 break;
3259 }
3260 case HorizontalTileEdgeVirtualPixelMethod:
3261 {
3262 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3263 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003264 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003265 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003266 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003267 break;
3268 }
3269 case VerticalTileEdgeVirtualPixelMethod:
3270 {
3271 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3272 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003273 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003274 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003275 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3276 break;
3277 }
3278 case BackgroundVirtualPixelMethod:
3279 case BlackVirtualPixelMethod:
3280 case GrayVirtualPixelMethod:
3281 case TransparentVirtualPixelMethod:
3282 case MaskVirtualPixelMethod:
3283 case WhiteVirtualPixelMethod:
3284 {
3285 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003286 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003287 break;
3288 }
3289 case EdgeVirtualPixelMethod:
3290 case CheckerTileVirtualPixelMethod:
3291 {
3292 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3293 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3294 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3295 {
3296 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003297 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003298 break;
3299 }
3300 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3301 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3302 exception);
3303 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3304 break;
3305 }
3306 case HorizontalTileVirtualPixelMethod:
3307 {
3308 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3309 {
3310 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003311 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003312 break;
3313 }
3314 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3315 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3316 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3317 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3318 exception);
3319 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3320 break;
3321 }
3322 case VerticalTileVirtualPixelMethod:
3323 {
3324 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3325 {
3326 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003327 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003328 break;
3329 }
3330 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3331 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3332 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3333 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3334 exception);
3335 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003336 break;
3337 }
3338 }
cristy4c08aed2011-07-01 19:47:50 +00003339 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003340 break;
cristyed231572011-07-14 02:18:59 +00003341 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003342 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003343 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003344 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003345 {
3346 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3347 s+=cache_info->metacontent_extent;
3348 }
cristy3ed852e2009-09-05 21:47:34 +00003349 continue;
3350 }
3351 /*
3352 Transfer a run of pixels.
3353 */
cristy4c08aed2011-07-01 19:47:50 +00003354 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3355 length,1UL,*virtual_nexus,exception);
3356 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003357 break;
cristy4c08aed2011-07-01 19:47:50 +00003358 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003359 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3360 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003361 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003362 {
cristy4c08aed2011-07-01 19:47:50 +00003363 (void) memcpy(s,r,(size_t) length);
3364 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003365 }
3366 }
3367 }
cristy4c08aed2011-07-01 19:47:50 +00003368 /*
3369 Free resources.
3370 */
cristy105ba3c2011-07-18 02:28:38 +00003371 if (virtual_metacontent != (void *) NULL)
3372 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003373 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3374 return(pixels);
3375}
3376
3377/*
3378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3379% %
3380% %
3381% %
3382+ G e t V i r t u a l P i x e l C a c h e %
3383% %
3384% %
3385% %
3386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3387%
3388% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3389% cache as defined by the geometry parameters. A pointer to the pixels
3390% is returned if the pixels are transferred, otherwise a NULL is returned.
3391%
3392% The format of the GetVirtualPixelCache() method is:
3393%
cristy4c08aed2011-07-01 19:47:50 +00003394% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003395% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3396% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003397% ExceptionInfo *exception)
3398%
3399% A description of each parameter follows:
3400%
3401% o image: the image.
3402%
3403% o virtual_pixel_method: the virtual pixel method.
3404%
3405% o x,y,columns,rows: These values define the perimeter of a region of
3406% pixels.
3407%
3408% o exception: return any errors or warnings in this structure.
3409%
3410*/
cristy4c08aed2011-07-01 19:47:50 +00003411static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003412 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3413 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003414{
3415 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003416 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003417
cristy5c9e6f22010-09-17 17:31:01 +00003418 const int
3419 id = GetOpenMPThreadId();
3420
cristy4c08aed2011-07-01 19:47:50 +00003421 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003422 *p;
cristy4c08aed2011-07-01 19:47:50 +00003423
cristye7cc7cf2010-09-21 13:26:47 +00003424 assert(image != (const Image *) NULL);
3425 assert(image->signature == MagickSignature);
3426 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003427 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003428 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003429 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003431 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003432 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003433}
3434
3435/*
3436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3437% %
3438% %
3439% %
3440% G e t V i r t u a l P i x e l Q u e u e %
3441% %
3442% %
3443% %
3444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3445%
cristy4c08aed2011-07-01 19:47:50 +00003446% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3447% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003448%
3449% The format of the GetVirtualPixelQueue() method is:
3450%
cristy4c08aed2011-07-01 19:47:50 +00003451% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003452%
3453% A description of each parameter follows:
3454%
3455% o image: the image.
3456%
3457*/
cristy4c08aed2011-07-01 19:47:50 +00003458MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003459{
3460 CacheInfo
3461 *cache_info;
3462
cristy2036f5c2010-09-19 21:18:17 +00003463 const int
3464 id = GetOpenMPThreadId();
3465
cristy3ed852e2009-09-05 21:47:34 +00003466 assert(image != (const Image *) NULL);
3467 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003468 assert(image->cache != (Cache) NULL);
3469 cache_info=(CacheInfo *) image->cache;
3470 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003471 if (cache_info->methods.get_virtual_pixels_handler !=
3472 (GetVirtualPixelsHandler) NULL)
3473 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003474 assert(id < (int) cache_info->number_threads);
3475 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003476}
3477
3478/*
3479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3480% %
3481% %
3482% %
3483% G e t V i r t u a l P i x e l s %
3484% %
3485% %
3486% %
3487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3488%
3489% GetVirtualPixels() returns an immutable pixel region. If the
3490% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003491% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003492% copy of the pixels or it may point to the original pixels in memory.
3493% Performance is maximized if the selected region is part of one row, or one
3494% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003495% (without a copy) if the image is in memory, or in a memory-mapped file. The
3496% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003497%
3498% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003499% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3500% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3501% access the meta-content (of type void) corresponding to the the
3502% region.
cristy3ed852e2009-09-05 21:47:34 +00003503%
3504% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3505%
3506% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3507% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3508% GetCacheViewAuthenticPixels() instead.
3509%
3510% The format of the GetVirtualPixels() method is:
3511%
cristy4c08aed2011-07-01 19:47:50 +00003512% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003513% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003514% ExceptionInfo *exception)
3515%
3516% A description of each parameter follows:
3517%
3518% o image: the image.
3519%
3520% o x,y,columns,rows: These values define the perimeter of a region of
3521% pixels.
3522%
3523% o exception: return any errors or warnings in this structure.
3524%
3525*/
cristy4c08aed2011-07-01 19:47:50 +00003526MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003527 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3528 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003529{
3530 CacheInfo
3531 *cache_info;
3532
cristy2036f5c2010-09-19 21:18:17 +00003533 const int
3534 id = GetOpenMPThreadId();
3535
cristy4c08aed2011-07-01 19:47:50 +00003536 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003537 *p;
cristy4c08aed2011-07-01 19:47:50 +00003538
cristy3ed852e2009-09-05 21:47:34 +00003539 assert(image != (const Image *) NULL);
3540 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003541 assert(image->cache != (Cache) NULL);
3542 cache_info=(CacheInfo *) image->cache;
3543 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003544 if (cache_info->methods.get_virtual_pixel_handler !=
3545 (GetVirtualPixelHandler) NULL)
3546 return(cache_info->methods.get_virtual_pixel_handler(image,
3547 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003548 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003549 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003550 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003551 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003552}
3553
3554/*
3555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3556% %
3557% %
3558% %
3559+ 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 %
3560% %
3561% %
3562% %
3563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3564%
cristy4c08aed2011-07-01 19:47:50 +00003565% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3566% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003567%
3568% The format of the GetVirtualPixelsCache() method is:
3569%
cristy4c08aed2011-07-01 19:47:50 +00003570% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003571%
3572% A description of each parameter follows:
3573%
3574% o image: the image.
3575%
3576*/
cristy4c08aed2011-07-01 19:47:50 +00003577static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003578{
3579 CacheInfo
3580 *cache_info;
3581
cristy5c9e6f22010-09-17 17:31:01 +00003582 const int
3583 id = GetOpenMPThreadId();
3584
cristye7cc7cf2010-09-21 13:26:47 +00003585 assert(image != (const Image *) NULL);
3586 assert(image->signature == MagickSignature);
3587 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003588 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003589 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003590 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003591 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003592}
3593
3594/*
3595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3596% %
3597% %
3598% %
3599+ G e t V i r t u a l P i x e l s N e x u s %
3600% %
3601% %
3602% %
3603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604%
3605% GetVirtualPixelsNexus() returns the pixels associated with the specified
3606% cache nexus.
3607%
3608% The format of the GetVirtualPixelsNexus() method is:
3609%
cristy4c08aed2011-07-01 19:47:50 +00003610% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003611% NexusInfo *nexus_info)
3612%
3613% A description of each parameter follows:
3614%
3615% o cache: the pixel cache.
3616%
3617% o nexus_info: the cache nexus to return the colormap pixels.
3618%
3619*/
cristya6577ff2011-09-02 19:54:26 +00003620MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003621 NexusInfo *nexus_info)
3622{
3623 CacheInfo
3624 *cache_info;
3625
cristye7cc7cf2010-09-21 13:26:47 +00003626 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003627 cache_info=(CacheInfo *) cache;
3628 assert(cache_info->signature == MagickSignature);
3629 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003630 return((Quantum *) NULL);
3631 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003632}
3633
3634/*
3635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3636% %
3637% %
3638% %
cristy3ed852e2009-09-05 21:47:34 +00003639+ O p e n P i x e l C a c h e %
3640% %
3641% %
3642% %
3643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3644%
3645% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3646% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003647% metacontent, and memory mapping the cache if it is disk based. The cache
3648% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003649%
3650% The format of the OpenPixelCache() method is:
3651%
3652% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3653% ExceptionInfo *exception)
3654%
3655% A description of each parameter follows:
3656%
3657% o image: the image.
3658%
3659% o mode: ReadMode, WriteMode, or IOMode.
3660%
3661% o exception: return any errors or warnings in this structure.
3662%
3663*/
3664
cristyd43a46b2010-01-21 02:13:41 +00003665static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003666{
3667 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003668 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003669 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003670 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003671 {
3672 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003673 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003674 cache_info->length);
3675 }
3676}
3677
3678static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3679{
3680 CacheInfo
3681 *cache_info;
3682
3683 MagickOffsetType
3684 count,
3685 extent,
3686 offset;
3687
3688 cache_info=(CacheInfo *) image->cache;
3689 if (image->debug != MagickFalse)
3690 {
3691 char
3692 format[MaxTextExtent],
3693 message[MaxTextExtent];
3694
cristyb9080c92009-12-01 20:13:26 +00003695 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003696 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003697 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003698 cache_info->cache_filename,cache_info->file,format);
3699 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3700 }
3701 if (length != (MagickSizeType) ((MagickOffsetType) length))
3702 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003703 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003704 if (extent < 0)
3705 return(MagickFalse);
3706 if ((MagickSizeType) extent >= length)
3707 return(MagickTrue);
3708 offset=(MagickOffsetType) length-1;
3709 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3710 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3711}
3712
3713static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3714 ExceptionInfo *exception)
3715{
cristy3ed852e2009-09-05 21:47:34 +00003716 CacheInfo
3717 *cache_info,
3718 source_info;
3719
cristyf3a6a9d2010-11-07 21:02:56 +00003720 char
3721 format[MaxTextExtent],
3722 message[MaxTextExtent];
3723
cristy4c08aed2011-07-01 19:47:50 +00003724 MagickBooleanType
3725 status;
3726
cristy3ed852e2009-09-05 21:47:34 +00003727 MagickSizeType
3728 length,
3729 number_pixels;
3730
cristy3b8fe922011-12-29 18:56:23 +00003731 PixelChannelMap
3732 *p,
3733 *q;
3734
cristy3ed852e2009-09-05 21:47:34 +00003735 size_t
cristye076a6e2010-08-15 19:59:43 +00003736 columns,
cristy3ed852e2009-09-05 21:47:34 +00003737 packet_size;
3738
cristye7cc7cf2010-09-21 13:26:47 +00003739 assert(image != (const Image *) NULL);
3740 assert(image->signature == MagickSignature);
3741 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003742 if (image->debug != MagickFalse)
3743 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3744 if ((image->columns == 0) || (image->rows == 0))
3745 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3746 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003747 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003748 source_info=(*cache_info);
3749 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003750 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003751 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003752 cache_info->storage_class=image->storage_class;
3753 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003754 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003755 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003756 cache_info->rows=image->rows;
3757 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003758 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003759 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003760 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3761 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003762 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003763 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003764 if (image->ping != MagickFalse)
3765 {
cristy73724512010-04-12 14:43:14 +00003766 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003767 cache_info->pixels=(Quantum *) NULL;
3768 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003769 cache_info->length=0;
3770 return(MagickTrue);
3771 }
cristy3ed852e2009-09-05 21:47:34 +00003772 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003773 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003774 if (image->metacontent_extent != 0)
3775 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003776 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003777 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003778 if (cache_info->columns != columns)
3779 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3780 image->filename);
3781 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00003782 p=cache_info->channel_map;
3783 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00003784 if ((cache_info->type != UndefinedCache) &&
3785 (cache_info->columns <= source_info.columns) &&
3786 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00003787 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00003788 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00003789 (cache_info->metacontent_extent <= source_info.metacontent_extent))
3790 {
3791 /*
3792 Inline pixel cache clone optimization.
3793 */
3794 if ((cache_info->columns == source_info.columns) &&
3795 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00003796 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00003797 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00003798 (cache_info->metacontent_extent == source_info.metacontent_extent))
3799 return(MagickTrue);
3800 return(ClonePixelCachePixels(cache_info,&source_info,exception));
3801 }
cristy3ed852e2009-09-05 21:47:34 +00003802 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003803 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003804 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003805 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3806 {
3807 status=AcquireMagickResource(MemoryResource,cache_info->length);
3808 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3809 (cache_info->type == MemoryCache))
3810 {
cristyd43a46b2010-01-21 02:13:41 +00003811 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003812 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003813 cache_info->pixels=source_info.pixels;
3814 else
3815 {
3816 /*
3817 Create memory pixel cache.
3818 */
cristy4c08aed2011-07-01 19:47:50 +00003819 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003820 if (image->debug != MagickFalse)
3821 {
cristy32cacff2011-12-31 03:36:27 +00003822 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003823 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003824 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3825 cache_info->filename,cache_info->mapped != MagickFalse ?
3826 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003827 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003828 format);
cristy3ed852e2009-09-05 21:47:34 +00003829 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3830 message);
3831 }
cristy3ed852e2009-09-05 21:47:34 +00003832 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003833 cache_info->metacontent=(void *) NULL;
3834 if (cache_info->metacontent_extent != 0)
3835 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003836 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003837 if ((source_info.storage_class != UndefinedClass) &&
3838 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003839 {
cristy4c08aed2011-07-01 19:47:50 +00003840 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003841 exception);
3842 RelinquishPixelCachePixels(&source_info);
3843 }
cristy4c08aed2011-07-01 19:47:50 +00003844 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003845 }
3846 }
3847 RelinquishMagickResource(MemoryResource,cache_info->length);
3848 }
3849 /*
3850 Create pixel cache on disk.
3851 */
3852 status=AcquireMagickResource(DiskResource,cache_info->length);
3853 if (status == MagickFalse)
3854 {
3855 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3856 "CacheResourcesExhausted","`%s'",image->filename);
3857 return(MagickFalse);
3858 }
cristy413f1302012-01-01 17:48:27 +00003859 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3860 {
3861 (void) ClosePixelCacheOnDisk(cache_info);
3862 *cache_info->cache_filename='\0';
3863 }
cristy3ed852e2009-09-05 21:47:34 +00003864 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3865 {
3866 RelinquishMagickResource(DiskResource,cache_info->length);
3867 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3868 image->filename);
3869 return(MagickFalse);
3870 }
3871 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3872 cache_info->length);
3873 if (status == MagickFalse)
3874 {
3875 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3876 image->filename);
3877 return(MagickFalse);
3878 }
cristyed231572011-07-14 02:18:59 +00003879 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003880 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003881 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003882 cache_info->type=DiskCache;
3883 else
3884 {
3885 status=AcquireMagickResource(MapResource,cache_info->length);
3886 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3887 (cache_info->type != MemoryCache))
3888 cache_info->type=DiskCache;
3889 else
3890 {
cristy4c08aed2011-07-01 19:47:50 +00003891 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003892 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003893 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003894 {
cristy3ed852e2009-09-05 21:47:34 +00003895 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003896 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003897 }
3898 else
3899 {
3900 /*
3901 Create file-backed memory-mapped pixel cache.
3902 */
cristy4c08aed2011-07-01 19:47:50 +00003903 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003904 (void) ClosePixelCacheOnDisk(cache_info);
3905 cache_info->type=MapCache;
3906 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003907 cache_info->metacontent=(void *) NULL;
3908 if (cache_info->metacontent_extent != 0)
3909 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003910 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003911 if ((source_info.storage_class != UndefinedClass) &&
3912 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003913 {
3914 status=ClonePixelCachePixels(cache_info,&source_info,
3915 exception);
3916 RelinquishPixelCachePixels(&source_info);
3917 }
3918 if (image->debug != MagickFalse)
3919 {
cristy413f1302012-01-01 17:48:27 +00003920 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003921 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003922 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003923 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003924 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003925 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003926 format);
cristy3ed852e2009-09-05 21:47:34 +00003927 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3928 message);
3929 }
cristy4c08aed2011-07-01 19:47:50 +00003930 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003931 }
3932 }
3933 RelinquishMagickResource(MapResource,cache_info->length);
3934 }
cristy4c08aed2011-07-01 19:47:50 +00003935 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003936 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003937 {
3938 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3939 RelinquishPixelCachePixels(&source_info);
3940 }
3941 if (image->debug != MagickFalse)
3942 {
cristyb9080c92009-12-01 20:13:26 +00003943 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003944 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003945 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003946 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003947 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003948 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003949 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3950 }
cristy4c08aed2011-07-01 19:47:50 +00003951 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003952}
3953
3954/*
3955%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3956% %
3957% %
3958% %
3959+ P e r s i s t P i x e l C a c h e %
3960% %
3961% %
3962% %
3963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3964%
3965% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3966% persistent pixel cache is one that resides on disk and is not destroyed
3967% when the program exits.
3968%
3969% The format of the PersistPixelCache() method is:
3970%
3971% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3972% const MagickBooleanType attach,MagickOffsetType *offset,
3973% ExceptionInfo *exception)
3974%
3975% A description of each parameter follows:
3976%
3977% o image: the image.
3978%
3979% o filename: the persistent pixel cache filename.
3980%
cristyf3a6a9d2010-11-07 21:02:56 +00003981% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003982%
cristy3ed852e2009-09-05 21:47:34 +00003983% o initialize: A value other than zero initializes the persistent pixel
3984% cache.
3985%
3986% o offset: the offset in the persistent cache to store pixels.
3987%
3988% o exception: return any errors or warnings in this structure.
3989%
3990*/
3991MagickExport MagickBooleanType PersistPixelCache(Image *image,
3992 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3993 ExceptionInfo *exception)
3994{
3995 CacheInfo
3996 *cache_info,
3997 *clone_info;
3998
3999 Image
4000 clone_image;
4001
cristy3ed852e2009-09-05 21:47:34 +00004002 MagickBooleanType
4003 status;
4004
cristye076a6e2010-08-15 19:59:43 +00004005 ssize_t
4006 page_size;
4007
cristy3ed852e2009-09-05 21:47:34 +00004008 assert(image != (Image *) NULL);
4009 assert(image->signature == MagickSignature);
4010 if (image->debug != MagickFalse)
4011 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4012 assert(image->cache != (void *) NULL);
4013 assert(filename != (const char *) NULL);
4014 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004015 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004016 cache_info=(CacheInfo *) image->cache;
4017 assert(cache_info->signature == MagickSignature);
4018 if (attach != MagickFalse)
4019 {
4020 /*
cristy01b7eb02009-09-10 23:10:14 +00004021 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004022 */
4023 if (image->debug != MagickFalse)
4024 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004025 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004026 (void) CopyMagickString(cache_info->cache_filename,filename,
4027 MaxTextExtent);
4028 cache_info->type=DiskCache;
4029 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004030 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004031 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004032 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004033 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004034 }
cristy01b7eb02009-09-10 23:10:14 +00004035 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4036 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004037 {
cristyf84a1932010-01-03 18:00:18 +00004038 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004039 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004040 (cache_info->reference_count == 1))
4041 {
4042 int
4043 status;
4044
4045 /*
cristy01b7eb02009-09-10 23:10:14 +00004046 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004047 */
cristy320684d2011-09-23 14:55:47 +00004048 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004049 if (status == 0)
4050 {
4051 (void) CopyMagickString(cache_info->cache_filename,filename,
4052 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004053 *offset+=cache_info->length+page_size-(cache_info->length %
4054 page_size);
cristyf84a1932010-01-03 18:00:18 +00004055 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004056 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004057 if (image->debug != MagickFalse)
4058 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4059 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004060 return(MagickTrue);
4061 }
4062 }
cristyf84a1932010-01-03 18:00:18 +00004063 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004064 }
4065 /*
cristy01b7eb02009-09-10 23:10:14 +00004066 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004067 */
4068 clone_image=(*image);
4069 clone_info=(CacheInfo *) clone_image.cache;
4070 image->cache=ClonePixelCache(cache_info);
4071 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4072 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4073 cache_info->type=DiskCache;
4074 cache_info->offset=(*offset);
4075 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004076 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004077 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004078 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004079 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004080 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4081 return(status);
4082}
4083
4084/*
4085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4086% %
4087% %
4088% %
cristyc11dace2012-01-24 16:39:46 +00004089+ 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 +00004090% %
4091% %
4092% %
4093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4094%
cristyc11dace2012-01-24 16:39:46 +00004095% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4096% defined by the region rectangle and returns a pointer to the region. This
4097% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004098% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4099% pixels are transferred, otherwise a NULL is returned.
4100%
cristyc11dace2012-01-24 16:39:46 +00004101% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004102%
cristyc11dace2012-01-24 16:39:46 +00004103% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004104% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004105% const MagickBooleanType clone,NexusInfo *nexus_info,
4106% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004107%
4108% A description of each parameter follows:
4109%
4110% o image: the image.
4111%
4112% o x,y,columns,rows: These values define the perimeter of a region of
4113% pixels.
4114%
4115% o nexus_info: the cache nexus to set.
4116%
cristy65dbf172011-10-06 17:32:04 +00004117% o clone: clone the pixel cache.
4118%
cristy3ed852e2009-09-05 21:47:34 +00004119% o exception: return any errors or warnings in this structure.
4120%
4121*/
cristyc11dace2012-01-24 16:39:46 +00004122MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4123 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004124 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004125{
4126 CacheInfo
4127 *cache_info;
4128
4129 MagickOffsetType
4130 offset;
4131
4132 MagickSizeType
4133 number_pixels;
4134
4135 RectangleInfo
4136 region;
4137
4138 /*
4139 Validate pixel cache geometry.
4140 */
cristye7cc7cf2010-09-21 13:26:47 +00004141 assert(image != (const Image *) NULL);
4142 assert(image->signature == MagickSignature);
4143 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004144 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004145 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004146 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004147 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004148 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4149 {
4150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4151 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004152 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004153 }
cristybb503372010-05-27 20:51:26 +00004154 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4155 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004156 {
4157 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4158 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004159 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004160 }
4161 offset=(MagickOffsetType) y*cache_info->columns+x;
4162 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004163 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004164 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4165 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4166 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004167 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004168 /*
4169 Return pixel cache.
4170 */
4171 region.x=x;
4172 region.y=y;
4173 region.width=columns;
4174 region.height=rows;
4175 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4176}
4177
4178/*
4179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4180% %
4181% %
4182% %
4183+ 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 %
4184% %
4185% %
4186% %
4187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4188%
4189% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4190% defined by the region rectangle and returns a pointer to the region. This
4191% region is subsequently transferred from the pixel cache with
4192% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4193% pixels are transferred, otherwise a NULL is returned.
4194%
4195% The format of the QueueAuthenticPixelsCache() method is:
4196%
cristy4c08aed2011-07-01 19:47:50 +00004197% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004198% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004199% ExceptionInfo *exception)
4200%
4201% A description of each parameter follows:
4202%
4203% o image: the image.
4204%
4205% o x,y,columns,rows: These values define the perimeter of a region of
4206% pixels.
4207%
4208% o exception: return any errors or warnings in this structure.
4209%
4210*/
cristy4c08aed2011-07-01 19:47:50 +00004211static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004212 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004213 ExceptionInfo *exception)
4214{
4215 CacheInfo
4216 *cache_info;
4217
cristy5c9e6f22010-09-17 17:31:01 +00004218 const int
4219 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004220
cristy4c08aed2011-07-01 19:47:50 +00004221 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004222 *q;
cristy4c08aed2011-07-01 19:47:50 +00004223
cristye7cc7cf2010-09-21 13:26:47 +00004224 assert(image != (const Image *) NULL);
4225 assert(image->signature == MagickSignature);
4226 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004227 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004228 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004229 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004230 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004231 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004232 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004233}
4234
4235/*
4236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4237% %
4238% %
4239% %
4240% Q u e u e A u t h e n t i c P i x e l s %
4241% %
4242% %
4243% %
4244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4245%
4246% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004247% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004248% region is returned, otherwise NULL is returned. The returned pointer may
4249% point to a temporary working buffer for the pixels or it may point to the
4250% final location of the pixels in memory.
4251%
4252% Write-only access means that any existing pixel values corresponding to
4253% the region are ignored. This is useful if the initial image is being
4254% created from scratch, or if the existing pixel values are to be
4255% completely replaced without need to refer to their pre-existing values.
4256% The application is free to read and write the pixel buffer returned by
4257% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4258% initialize the pixel array values. Initializing pixel array values is the
4259% application's responsibility.
4260%
4261% Performance is maximized if the selected region is part of one row, or
4262% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004263% pixels in-place (without a copy) if the image is in memory, or in a
4264% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004265% by the user.
4266%
4267% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004268% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4269% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4270% obtain the meta-content (of type void) corresponding to the region.
4271% Once the Quantum (and/or Quantum) array has been updated, the
4272% changes must be saved back to the underlying image using
4273% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004274%
4275% The format of the QueueAuthenticPixels() method is:
4276%
cristy4c08aed2011-07-01 19:47:50 +00004277% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004278% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004279% ExceptionInfo *exception)
4280%
4281% A description of each parameter follows:
4282%
4283% o image: the image.
4284%
4285% o x,y,columns,rows: These values define the perimeter of a region of
4286% pixels.
4287%
4288% o exception: return any errors or warnings in this structure.
4289%
4290*/
cristy4c08aed2011-07-01 19:47:50 +00004291MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004292 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004293 ExceptionInfo *exception)
4294{
4295 CacheInfo
4296 *cache_info;
4297
cristy2036f5c2010-09-19 21:18:17 +00004298 const int
4299 id = GetOpenMPThreadId();
4300
cristy4c08aed2011-07-01 19:47:50 +00004301 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004302 *q;
cristy4c08aed2011-07-01 19:47:50 +00004303
cristy3ed852e2009-09-05 21:47:34 +00004304 assert(image != (Image *) NULL);
4305 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004306 assert(image->cache != (Cache) NULL);
4307 cache_info=(CacheInfo *) image->cache;
4308 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004309 if (cache_info->methods.queue_authentic_pixels_handler !=
4310 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004311 {
cristyacd2ed22011-08-30 01:44:23 +00004312 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004313 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004314 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004315 }
cristy2036f5c2010-09-19 21:18:17 +00004316 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004317 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004318 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004319 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004320}
4321
4322/*
4323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4324% %
4325% %
4326% %
cristy4c08aed2011-07-01 19:47:50 +00004327+ 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 +00004328% %
4329% %
4330% %
4331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4332%
cristy4c08aed2011-07-01 19:47:50 +00004333% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004334% the pixel cache.
4335%
cristy4c08aed2011-07-01 19:47:50 +00004336% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004337%
cristy4c08aed2011-07-01 19:47:50 +00004338% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004339% NexusInfo *nexus_info,ExceptionInfo *exception)
4340%
4341% A description of each parameter follows:
4342%
4343% o cache_info: the pixel cache.
4344%
cristy4c08aed2011-07-01 19:47:50 +00004345% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004346%
4347% o exception: return any errors or warnings in this structure.
4348%
4349*/
cristy4c08aed2011-07-01 19:47:50 +00004350static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004351 NexusInfo *nexus_info,ExceptionInfo *exception)
4352{
4353 MagickOffsetType
4354 count,
4355 offset;
4356
4357 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004358 extent,
4359 length;
cristy3ed852e2009-09-05 21:47:34 +00004360
cristybb503372010-05-27 20:51:26 +00004361 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004362 y;
4363
cristy4c08aed2011-07-01 19:47:50 +00004364 register unsigned char
4365 *restrict q;
4366
cristybb503372010-05-27 20:51:26 +00004367 size_t
cristy3ed852e2009-09-05 21:47:34 +00004368 rows;
4369
cristy4c08aed2011-07-01 19:47:50 +00004370 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004371 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004372 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004373 return(MagickTrue);
4374 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4375 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004376 length=(MagickSizeType) nexus_info->region.width*
4377 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004378 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004379 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004380 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004381 switch (cache_info->type)
4382 {
4383 case MemoryCache:
4384 case MapCache:
4385 {
cristy4c08aed2011-07-01 19:47:50 +00004386 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004387 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004388
4389 /*
cristy4c08aed2011-07-01 19:47:50 +00004390 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004391 */
cristydd341db2010-03-04 19:06:38 +00004392 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004393 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004394 {
cristy48078b12010-09-23 17:11:01 +00004395 length=extent;
cristydd341db2010-03-04 19:06:38 +00004396 rows=1UL;
4397 }
cristy4c08aed2011-07-01 19:47:50 +00004398 p=(unsigned char *) cache_info->metacontent+offset*
4399 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004400 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004401 {
cristy8f036fe2010-09-18 02:02:00 +00004402 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004403 p+=cache_info->metacontent_extent*cache_info->columns;
4404 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004405 }
4406 break;
4407 }
4408 case DiskCache:
4409 {
4410 /*
cristy4c08aed2011-07-01 19:47:50 +00004411 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004412 */
4413 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4414 {
4415 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4416 cache_info->cache_filename);
4417 return(MagickFalse);
4418 }
cristydd341db2010-03-04 19:06:38 +00004419 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004420 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004421 {
cristy48078b12010-09-23 17:11:01 +00004422 length=extent;
cristydd341db2010-03-04 19:06:38 +00004423 rows=1UL;
4424 }
cristy48078b12010-09-23 17:11:01 +00004425 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004426 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004427 {
cristy48078b12010-09-23 17:11:01 +00004428 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004429 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004430 cache_info->metacontent_extent,length,(unsigned char *) q);
4431 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004432 break;
4433 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004434 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004435 }
cristyc11dace2012-01-24 16:39:46 +00004436 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4437 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004438 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004439 {
4440 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4441 cache_info->cache_filename);
4442 return(MagickFalse);
4443 }
4444 break;
4445 }
4446 default:
4447 break;
4448 }
4449 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004450 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004451 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004452 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004453 nexus_info->region.width,(double) nexus_info->region.height,(double)
4454 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004455 return(MagickTrue);
4456}
4457
4458/*
4459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4460% %
4461% %
4462% %
4463+ R e a d P i x e l C a c h e P i x e l s %
4464% %
4465% %
4466% %
4467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4468%
4469% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4470% cache.
4471%
4472% The format of the ReadPixelCachePixels() method is:
4473%
4474% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4475% NexusInfo *nexus_info,ExceptionInfo *exception)
4476%
4477% A description of each parameter follows:
4478%
4479% o cache_info: the pixel cache.
4480%
4481% o nexus_info: the cache nexus to read the pixels.
4482%
4483% o exception: return any errors or warnings in this structure.
4484%
4485*/
4486static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4487 NexusInfo *nexus_info,ExceptionInfo *exception)
4488{
4489 MagickOffsetType
4490 count,
4491 offset;
4492
4493 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004494 extent,
4495 length;
cristy3ed852e2009-09-05 21:47:34 +00004496
cristy4c08aed2011-07-01 19:47:50 +00004497 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004498 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004499
cristye076a6e2010-08-15 19:59:43 +00004500 register ssize_t
4501 y;
4502
cristybb503372010-05-27 20:51:26 +00004503 size_t
cristy3ed852e2009-09-05 21:47:34 +00004504 rows;
4505
cristy4c08aed2011-07-01 19:47:50 +00004506 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004507 return(MagickTrue);
4508 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4509 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004510 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004511 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004512 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004513 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004514 q=nexus_info->pixels;
4515 switch (cache_info->type)
4516 {
4517 case MemoryCache:
4518 case MapCache:
4519 {
cristy4c08aed2011-07-01 19:47:50 +00004520 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004521 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004522
4523 /*
4524 Read pixels from memory.
4525 */
cristydd341db2010-03-04 19:06:38 +00004526 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004527 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004528 {
cristy48078b12010-09-23 17:11:01 +00004529 length=extent;
cristydd341db2010-03-04 19:06:38 +00004530 rows=1UL;
4531 }
cristyed231572011-07-14 02:18:59 +00004532 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004533 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004534 {
cristy8f036fe2010-09-18 02:02:00 +00004535 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004536 p+=cache_info->number_channels*cache_info->columns;
4537 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004538 }
4539 break;
4540 }
4541 case DiskCache:
4542 {
4543 /*
4544 Read pixels from disk.
4545 */
4546 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4547 {
4548 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4549 cache_info->cache_filename);
4550 return(MagickFalse);
4551 }
cristydd341db2010-03-04 19:06:38 +00004552 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004553 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004554 {
cristy48078b12010-09-23 17:11:01 +00004555 length=extent;
cristydd341db2010-03-04 19:06:38 +00004556 rows=1UL;
4557 }
cristybb503372010-05-27 20:51:26 +00004558 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004559 {
4560 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004561 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004562 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004563 break;
4564 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004565 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004566 }
cristyc11dace2012-01-24 16:39:46 +00004567 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4568 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004569 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004570 {
4571 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4572 cache_info->cache_filename);
4573 return(MagickFalse);
4574 }
4575 break;
4576 }
4577 default:
4578 break;
4579 }
4580 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004581 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004582 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004583 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004584 nexus_info->region.width,(double) nexus_info->region.height,(double)
4585 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004586 return(MagickTrue);
4587}
4588
4589/*
4590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4591% %
4592% %
4593% %
4594+ R e f e r e n c e P i x e l C a c h e %
4595% %
4596% %
4597% %
4598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4599%
4600% ReferencePixelCache() increments the reference count associated with the
4601% pixel cache returning a pointer to the cache.
4602%
4603% The format of the ReferencePixelCache method is:
4604%
4605% Cache ReferencePixelCache(Cache cache_info)
4606%
4607% A description of each parameter follows:
4608%
4609% o cache_info: the pixel cache.
4610%
4611*/
cristya6577ff2011-09-02 19:54:26 +00004612MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004613{
4614 CacheInfo
4615 *cache_info;
4616
4617 assert(cache != (Cache *) NULL);
4618 cache_info=(CacheInfo *) cache;
4619 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004620 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004621 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004622 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004623 return(cache_info);
4624}
4625
4626/*
4627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4628% %
4629% %
4630% %
4631+ S e t P i x e l C a c h e M e t h o d s %
4632% %
4633% %
4634% %
4635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4636%
4637% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4638%
4639% The format of the SetPixelCacheMethods() method is:
4640%
4641% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4642%
4643% A description of each parameter follows:
4644%
4645% o cache: the pixel cache.
4646%
4647% o cache_methods: Specifies a pointer to a CacheMethods structure.
4648%
4649*/
cristya6577ff2011-09-02 19:54:26 +00004650MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004651{
4652 CacheInfo
4653 *cache_info;
4654
4655 GetOneAuthenticPixelFromHandler
4656 get_one_authentic_pixel_from_handler;
4657
4658 GetOneVirtualPixelFromHandler
4659 get_one_virtual_pixel_from_handler;
4660
4661 /*
4662 Set cache pixel methods.
4663 */
4664 assert(cache != (Cache) NULL);
4665 assert(cache_methods != (CacheMethods *) NULL);
4666 cache_info=(CacheInfo *) cache;
4667 assert(cache_info->signature == MagickSignature);
4668 if (cache_info->debug != MagickFalse)
4669 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4670 cache_info->filename);
4671 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4672 cache_info->methods.get_virtual_pixel_handler=
4673 cache_methods->get_virtual_pixel_handler;
4674 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4675 cache_info->methods.destroy_pixel_handler=
4676 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004677 if (cache_methods->get_virtual_metacontent_from_handler !=
4678 (GetVirtualMetacontentFromHandler) NULL)
4679 cache_info->methods.get_virtual_metacontent_from_handler=
4680 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004681 if (cache_methods->get_authentic_pixels_handler !=
4682 (GetAuthenticPixelsHandler) NULL)
4683 cache_info->methods.get_authentic_pixels_handler=
4684 cache_methods->get_authentic_pixels_handler;
4685 if (cache_methods->queue_authentic_pixels_handler !=
4686 (QueueAuthenticPixelsHandler) NULL)
4687 cache_info->methods.queue_authentic_pixels_handler=
4688 cache_methods->queue_authentic_pixels_handler;
4689 if (cache_methods->sync_authentic_pixels_handler !=
4690 (SyncAuthenticPixelsHandler) NULL)
4691 cache_info->methods.sync_authentic_pixels_handler=
4692 cache_methods->sync_authentic_pixels_handler;
4693 if (cache_methods->get_authentic_pixels_from_handler !=
4694 (GetAuthenticPixelsFromHandler) NULL)
4695 cache_info->methods.get_authentic_pixels_from_handler=
4696 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004697 if (cache_methods->get_authentic_metacontent_from_handler !=
4698 (GetAuthenticMetacontentFromHandler) NULL)
4699 cache_info->methods.get_authentic_metacontent_from_handler=
4700 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004701 get_one_virtual_pixel_from_handler=
4702 cache_info->methods.get_one_virtual_pixel_from_handler;
4703 if (get_one_virtual_pixel_from_handler !=
4704 (GetOneVirtualPixelFromHandler) NULL)
4705 cache_info->methods.get_one_virtual_pixel_from_handler=
4706 cache_methods->get_one_virtual_pixel_from_handler;
4707 get_one_authentic_pixel_from_handler=
4708 cache_methods->get_one_authentic_pixel_from_handler;
4709 if (get_one_authentic_pixel_from_handler !=
4710 (GetOneAuthenticPixelFromHandler) NULL)
4711 cache_info->methods.get_one_authentic_pixel_from_handler=
4712 cache_methods->get_one_authentic_pixel_from_handler;
4713}
4714
4715/*
4716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4717% %
4718% %
4719% %
4720+ S e t P i x e l C a c h e N e x u s P i x e l s %
4721% %
4722% %
4723% %
4724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4725%
4726% SetPixelCacheNexusPixels() defines the region of the cache for the
4727% specified cache nexus.
4728%
4729% The format of the SetPixelCacheNexusPixels() method is:
4730%
cristy4c08aed2011-07-01 19:47:50 +00004731% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004732% const RectangleInfo *region,NexusInfo *nexus_info,
4733% ExceptionInfo *exception)
4734%
4735% A description of each parameter follows:
4736%
4737% o image: the image.
4738%
4739% o region: A pointer to the RectangleInfo structure that defines the
4740% region of this particular cache nexus.
4741%
4742% o nexus_info: the cache nexus to set.
4743%
4744% o exception: return any errors or warnings in this structure.
4745%
4746*/
cristyabd6e372010-09-15 19:11:26 +00004747
4748static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4749 NexusInfo *nexus_info,ExceptionInfo *exception)
4750{
4751 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4752 return(MagickFalse);
4753 nexus_info->mapped=MagickFalse;
cristy7dc8ac52012-01-10 20:14:52 +00004754 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004755 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004756 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004757 {
4758 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004759 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004760 nexus_info->length);
4761 }
cristy4c08aed2011-07-01 19:47:50 +00004762 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004763 {
4764 (void) ThrowMagickException(exception,GetMagickModule(),
4765 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4766 cache_info->filename);
4767 return(MagickFalse);
4768 }
4769 return(MagickTrue);
4770}
4771
cristy4c08aed2011-07-01 19:47:50 +00004772static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004773 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4774{
4775 CacheInfo
4776 *cache_info;
4777
4778 MagickBooleanType
4779 status;
4780
cristy3ed852e2009-09-05 21:47:34 +00004781 MagickSizeType
4782 length,
4783 number_pixels;
4784
cristy3ed852e2009-09-05 21:47:34 +00004785 cache_info=(CacheInfo *) image->cache;
4786 assert(cache_info->signature == MagickSignature);
4787 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004788 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004789 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004790 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004791 {
cristybb503372010-05-27 20:51:26 +00004792 ssize_t
cristybad067a2010-02-15 17:20:55 +00004793 x,
4794 y;
cristy3ed852e2009-09-05 21:47:34 +00004795
cristyeaedf062010-05-29 22:36:02 +00004796 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4797 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004798 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4799 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004800 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004801 ((nexus_info->region.width == cache_info->columns) ||
4802 ((nexus_info->region.width % cache_info->columns) == 0)))))
4803 {
4804 MagickOffsetType
4805 offset;
4806
4807 /*
4808 Pixels are accessed directly from memory.
4809 */
4810 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4811 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004812 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004813 offset;
4814 nexus_info->metacontent=(void *) NULL;
4815 if (cache_info->metacontent_extent != 0)
4816 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4817 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00004818 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004819 }
4820 }
4821 /*
4822 Pixels are stored in a cache region until they are synced to the cache.
4823 */
4824 number_pixels=(MagickSizeType) nexus_info->region.width*
4825 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004826 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004827 if (cache_info->metacontent_extent != 0)
4828 length+=number_pixels*cache_info->metacontent_extent;
4829 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004830 {
4831 nexus_info->length=length;
4832 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4833 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004834 {
4835 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004836 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004837 }
cristy3ed852e2009-09-05 21:47:34 +00004838 }
4839 else
4840 if (nexus_info->length != length)
4841 {
4842 RelinquishCacheNexusPixels(nexus_info);
4843 nexus_info->length=length;
4844 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4845 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004846 {
4847 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004848 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004849 }
cristy3ed852e2009-09-05 21:47:34 +00004850 }
4851 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004852 nexus_info->metacontent=(void *) NULL;
4853 if (cache_info->metacontent_extent != 0)
4854 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004855 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004856 return(nexus_info->pixels);
4857}
4858
4859/*
4860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4861% %
4862% %
4863% %
4864% 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 %
4865% %
4866% %
4867% %
4868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4869%
4870% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4871% pixel cache and returns the previous setting. A virtual pixel is any pixel
4872% access that is outside the boundaries of the image cache.
4873%
4874% The format of the SetPixelCacheVirtualMethod() method is:
4875%
4876% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4877% const VirtualPixelMethod virtual_pixel_method)
4878%
4879% A description of each parameter follows:
4880%
4881% o image: the image.
4882%
4883% o virtual_pixel_method: choose the type of virtual pixel.
4884%
4885*/
cristyd1dd6e42011-09-04 01:46:08 +00004886MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004887 const VirtualPixelMethod virtual_pixel_method)
4888{
4889 CacheInfo
4890 *cache_info;
4891
4892 VirtualPixelMethod
4893 method;
4894
4895 assert(image != (Image *) NULL);
4896 assert(image->signature == MagickSignature);
4897 if (image->debug != MagickFalse)
4898 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4899 assert(image->cache != (Cache) NULL);
4900 cache_info=(CacheInfo *) image->cache;
4901 assert(cache_info->signature == MagickSignature);
4902 method=cache_info->virtual_pixel_method;
4903 cache_info->virtual_pixel_method=virtual_pixel_method;
4904 return(method);
4905}
4906
4907/*
4908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4909% %
4910% %
4911% %
4912+ 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 %
4913% %
4914% %
4915% %
4916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4917%
4918% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4919% in-memory or disk cache. The method returns MagickTrue if the pixel region
4920% is synced, otherwise MagickFalse.
4921%
4922% The format of the SyncAuthenticPixelCacheNexus() method is:
4923%
4924% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4925% NexusInfo *nexus_info,ExceptionInfo *exception)
4926%
4927% A description of each parameter follows:
4928%
4929% o image: the image.
4930%
4931% o nexus_info: the cache nexus to sync.
4932%
4933% o exception: return any errors or warnings in this structure.
4934%
4935*/
cristya6577ff2011-09-02 19:54:26 +00004936MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004937 NexusInfo *nexus_info,ExceptionInfo *exception)
4938{
4939 CacheInfo
4940 *cache_info;
4941
4942 MagickBooleanType
4943 status;
4944
4945 /*
4946 Transfer pixels to the cache.
4947 */
4948 assert(image != (Image *) NULL);
4949 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004950 if (image->cache == (Cache) NULL)
4951 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4952 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004953 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004954 if (cache_info->type == UndefinedCache)
4955 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004956 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004957 return(MagickTrue);
4958 assert(cache_info->signature == MagickSignature);
4959 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00004960 if ((cache_info->metacontent_extent != 0) &&
4961 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00004962 return(MagickFalse);
4963 return(status);
4964}
4965
4966/*
4967%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4968% %
4969% %
4970% %
4971+ S y n c A u t h e n t i c P i x e l C a c h e %
4972% %
4973% %
4974% %
4975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4976%
4977% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4978% or disk cache. The method returns MagickTrue if the pixel region is synced,
4979% otherwise MagickFalse.
4980%
4981% The format of the SyncAuthenticPixelsCache() method is:
4982%
4983% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4984% ExceptionInfo *exception)
4985%
4986% A description of each parameter follows:
4987%
4988% o image: the image.
4989%
4990% o exception: return any errors or warnings in this structure.
4991%
4992*/
4993static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4994 ExceptionInfo *exception)
4995{
4996 CacheInfo
4997 *cache_info;
4998
cristy5c9e6f22010-09-17 17:31:01 +00004999 const int
5000 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005001
cristy4c08aed2011-07-01 19:47:50 +00005002 MagickBooleanType
5003 status;
5004
cristye7cc7cf2010-09-21 13:26:47 +00005005 assert(image != (Image *) NULL);
5006 assert(image->signature == MagickSignature);
5007 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005008 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005009 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005010 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005011 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5012 exception);
5013 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005014}
5015
5016/*
5017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5018% %
5019% %
5020% %
5021% S y n c A u t h e n t i c P i x e l s %
5022% %
5023% %
5024% %
5025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5026%
5027% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5028% The method returns MagickTrue if the pixel region is flushed, otherwise
5029% MagickFalse.
5030%
5031% The format of the SyncAuthenticPixels() method is:
5032%
5033% MagickBooleanType SyncAuthenticPixels(Image *image,
5034% ExceptionInfo *exception)
5035%
5036% A description of each parameter follows:
5037%
5038% o image: the image.
5039%
5040% o exception: return any errors or warnings in this structure.
5041%
5042*/
5043MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5044 ExceptionInfo *exception)
5045{
5046 CacheInfo
5047 *cache_info;
5048
cristy2036f5c2010-09-19 21:18:17 +00005049 const int
5050 id = GetOpenMPThreadId();
5051
cristy4c08aed2011-07-01 19:47:50 +00005052 MagickBooleanType
5053 status;
5054
cristy3ed852e2009-09-05 21:47:34 +00005055 assert(image != (Image *) NULL);
5056 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005057 assert(image->cache != (Cache) NULL);
5058 cache_info=(CacheInfo *) image->cache;
5059 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005060 if (cache_info->methods.sync_authentic_pixels_handler !=
5061 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005062 {
5063 status=cache_info->methods.sync_authentic_pixels_handler(image,
5064 exception);
5065 return(status);
5066 }
cristy2036f5c2010-09-19 21:18:17 +00005067 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005068 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5069 exception);
5070 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005071}
5072
5073/*
5074%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5075% %
5076% %
5077% %
cristyd1dd6e42011-09-04 01:46:08 +00005078+ 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 +00005079% %
5080% %
5081% %
5082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5083%
5084% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5085% The method returns MagickTrue if the pixel region is flushed, otherwise
5086% MagickFalse.
5087%
5088% The format of the SyncImagePixelCache() method is:
5089%
5090% MagickBooleanType SyncImagePixelCache(Image *image,
5091% ExceptionInfo *exception)
5092%
5093% A description of each parameter follows:
5094%
5095% o image: the image.
5096%
5097% o exception: return any errors or warnings in this structure.
5098%
5099*/
cristyd1dd6e42011-09-04 01:46:08 +00005100MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005101 ExceptionInfo *exception)
5102{
5103 CacheInfo
5104 *cache_info;
5105
5106 assert(image != (Image *) NULL);
5107 assert(exception != (ExceptionInfo *) NULL);
5108 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5109 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5110}
5111
5112/*
5113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5114% %
5115% %
5116% %
cristy4c08aed2011-07-01 19:47:50 +00005117+ 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 +00005118% %
5119% %
5120% %
5121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5122%
cristy4c08aed2011-07-01 19:47:50 +00005123% WritePixelCacheMetacontent() writes the meta-content to the specified region
5124% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005125%
cristy4c08aed2011-07-01 19:47:50 +00005126% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005127%
cristy4c08aed2011-07-01 19:47:50 +00005128% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005129% NexusInfo *nexus_info,ExceptionInfo *exception)
5130%
5131% A description of each parameter follows:
5132%
5133% o cache_info: the pixel cache.
5134%
cristy4c08aed2011-07-01 19:47:50 +00005135% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005136%
5137% o exception: return any errors or warnings in this structure.
5138%
5139*/
cristy4c08aed2011-07-01 19:47:50 +00005140static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005141 NexusInfo *nexus_info,ExceptionInfo *exception)
5142{
5143 MagickOffsetType
5144 count,
5145 offset;
5146
5147 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005148 extent,
5149 length;
cristy3ed852e2009-09-05 21:47:34 +00005150
cristy4c08aed2011-07-01 19:47:50 +00005151 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005152 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005153
cristybb503372010-05-27 20:51:26 +00005154 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005155 y;
5156
cristybb503372010-05-27 20:51:26 +00005157 size_t
cristy3ed852e2009-09-05 21:47:34 +00005158 rows;
5159
cristy4c08aed2011-07-01 19:47:50 +00005160 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005161 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005162 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005163 return(MagickTrue);
5164 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5165 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005166 length=(MagickSizeType) nexus_info->region.width*
5167 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005168 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005169 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005170 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005171 switch (cache_info->type)
5172 {
5173 case MemoryCache:
5174 case MapCache:
5175 {
cristy4c08aed2011-07-01 19:47:50 +00005176 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005177 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005178
5179 /*
cristy4c08aed2011-07-01 19:47:50 +00005180 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005181 */
cristydd341db2010-03-04 19:06:38 +00005182 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005183 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005184 {
cristy48078b12010-09-23 17:11:01 +00005185 length=extent;
cristydd341db2010-03-04 19:06:38 +00005186 rows=1UL;
5187 }
cristy4c08aed2011-07-01 19:47:50 +00005188 q=(unsigned char *) cache_info->metacontent+offset*
5189 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005190 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005191 {
cristy8f036fe2010-09-18 02:02:00 +00005192 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005193 p+=nexus_info->region.width*cache_info->metacontent_extent;
5194 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005195 }
5196 break;
5197 }
5198 case DiskCache:
5199 {
5200 /*
cristy4c08aed2011-07-01 19:47:50 +00005201 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005202 */
5203 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5204 {
5205 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5206 cache_info->cache_filename);
5207 return(MagickFalse);
5208 }
cristydd341db2010-03-04 19:06:38 +00005209 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005210 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005211 {
cristy48078b12010-09-23 17:11:01 +00005212 length=extent;
cristydd341db2010-03-04 19:06:38 +00005213 rows=1UL;
5214 }
cristy48078b12010-09-23 17:11:01 +00005215 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005216 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005217 {
cristy48078b12010-09-23 17:11:01 +00005218 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005219 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005220 cache_info->metacontent_extent,length,(const unsigned char *) p);
5221 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005222 break;
cristy4c08aed2011-07-01 19:47:50 +00005223 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005224 offset+=cache_info->columns;
5225 }
cristyc11dace2012-01-24 16:39:46 +00005226 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5227 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005228 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005229 {
5230 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5231 cache_info->cache_filename);
5232 return(MagickFalse);
5233 }
5234 break;
5235 }
5236 default:
5237 break;
5238 }
5239 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005240 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005241 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005242 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005243 nexus_info->region.width,(double) nexus_info->region.height,(double)
5244 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005245 return(MagickTrue);
5246}
5247
5248/*
5249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5250% %
5251% %
5252% %
5253+ W r i t e C a c h e P i x e l s %
5254% %
5255% %
5256% %
5257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5258%
5259% WritePixelCachePixels() writes image pixels to the specified region of the
5260% pixel cache.
5261%
5262% The format of the WritePixelCachePixels() method is:
5263%
5264% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5265% NexusInfo *nexus_info,ExceptionInfo *exception)
5266%
5267% A description of each parameter follows:
5268%
5269% o cache_info: the pixel cache.
5270%
5271% o nexus_info: the cache nexus to write the pixels.
5272%
5273% o exception: return any errors or warnings in this structure.
5274%
5275*/
5276static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5277 NexusInfo *nexus_info,ExceptionInfo *exception)
5278{
5279 MagickOffsetType
5280 count,
5281 offset;
5282
5283 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005284 extent,
5285 length;
cristy3ed852e2009-09-05 21:47:34 +00005286
cristy4c08aed2011-07-01 19:47:50 +00005287 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005288 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005289
cristybb503372010-05-27 20:51:26 +00005290 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005291 y;
5292
cristybb503372010-05-27 20:51:26 +00005293 size_t
cristy3ed852e2009-09-05 21:47:34 +00005294 rows;
5295
cristy4c08aed2011-07-01 19:47:50 +00005296 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005297 return(MagickTrue);
5298 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5299 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005300 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005301 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005302 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005303 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005304 p=nexus_info->pixels;
5305 switch (cache_info->type)
5306 {
5307 case MemoryCache:
5308 case MapCache:
5309 {
cristy4c08aed2011-07-01 19:47:50 +00005310 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005311 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005312
5313 /*
5314 Write pixels to memory.
5315 */
cristydd341db2010-03-04 19:06:38 +00005316 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005317 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005318 {
cristy48078b12010-09-23 17:11:01 +00005319 length=extent;
cristydd341db2010-03-04 19:06:38 +00005320 rows=1UL;
5321 }
cristyed231572011-07-14 02:18:59 +00005322 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005323 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005324 {
cristy8f036fe2010-09-18 02:02:00 +00005325 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005326 p+=nexus_info->region.width*cache_info->number_channels;
5327 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005328 }
5329 break;
5330 }
5331 case DiskCache:
5332 {
5333 /*
5334 Write pixels to disk.
5335 */
5336 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5337 {
5338 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5339 cache_info->cache_filename);
5340 return(MagickFalse);
5341 }
cristydd341db2010-03-04 19:06:38 +00005342 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005343 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005344 {
cristy48078b12010-09-23 17:11:01 +00005345 length=extent;
cristydd341db2010-03-04 19:06:38 +00005346 rows=1UL;
5347 }
cristybb503372010-05-27 20:51:26 +00005348 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005349 {
5350 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005351 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005352 p);
5353 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005354 break;
cristyed231572011-07-14 02:18:59 +00005355 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005356 offset+=cache_info->columns;
5357 }
cristyc11dace2012-01-24 16:39:46 +00005358 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5359 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005360 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005361 {
5362 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5363 cache_info->cache_filename);
5364 return(MagickFalse);
5365 }
5366 break;
5367 }
5368 default:
5369 break;
5370 }
5371 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005372 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005373 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005374 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005375 nexus_info->region.width,(double) nexus_info->region.height,(double)
5376 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005377 return(MagickTrue);
5378}