blob: 906825afc39ace754fecbde63ed1676c8dfd59d6 [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
cristy19596d62012-02-19 00:24:59 +0000120static Cache
121 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
122 magick_hot_spot;
123
cristy4c08aed2011-07-01 19:47:50 +0000124static const Quantum
cristybb503372010-05-27 20:51:26 +0000125 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000126 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000127 *GetVirtualPixelsCache(const Image *);
128
cristy4c08aed2011-07-01 19:47:50 +0000129static const void
130 *GetVirtualMetacontentFromCache(const Image *);
131
cristy3ed852e2009-09-05 21:47:34 +0000132static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000133 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000134 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000135 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000136 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000137 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000138 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000139 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
140 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000141 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
143
cristy4c08aed2011-07-01 19:47:50 +0000144static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000145 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
146 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000147 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
148 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000149 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristy19596d62012-02-19 00:24:59 +0000150 ExceptionInfo *) magick_hot_spot;
cristy3ed852e2009-09-05 21:47:34 +0000151
152#if defined(__cplusplus) || defined(c_plusplus)
153}
154#endif
155
156/*
157 Global declarations.
158*/
159static volatile MagickBooleanType
160 instantiate_cache = MagickFalse;
161
162static SemaphoreInfo
163 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000164
165/*
166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167% %
168% %
169% %
170+ A c q u i r e P i x e l C a c h e %
171% %
172% %
173% %
174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
175%
176% AcquirePixelCache() acquires a pixel cache.
177%
178% The format of the AcquirePixelCache() method is:
179%
cristybb503372010-05-27 20:51:26 +0000180% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000181%
182% A description of each parameter follows:
183%
184% o number_threads: the number of nexus threads.
185%
186*/
cristya6577ff2011-09-02 19:54:26 +0000187MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000188{
189 CacheInfo
190 *cache_info;
191
cristya64b85d2011-09-14 01:02:31 +0000192 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000193 if (cache_info == (CacheInfo *) NULL)
194 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
195 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
196 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000197 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000198 cache_info->colorspace=RGBColorspace;
199 cache_info->file=(-1);
200 cache_info->id=GetMagickThreadId();
201 cache_info->number_threads=number_threads;
202 if (number_threads == 0)
203 cache_info->number_threads=GetOpenMPMaximumThreads();
204 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
205 if (cache_info->nexus_info == (NexusInfo **) NULL)
206 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000207 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000208 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000209 cache_info->disk_semaphore=AllocateSemaphoreInfo();
210 cache_info->debug=IsEventLogging();
211 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000212 return((Cache ) cache_info);
213}
214
215/*
216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217% %
218% %
219% %
220% A c q u i r e P i x e l C a c h e N e x u s %
221% %
222% %
223% %
224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225%
226% AcquirePixelCacheNexus() allocates the NexusInfo structure.
227%
228% The format of the AcquirePixelCacheNexus method is:
229%
cristybb503372010-05-27 20:51:26 +0000230% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000231%
232% A description of each parameter follows:
233%
234% o number_threads: the number of nexus threads.
235%
236*/
cristya6577ff2011-09-02 19:54:26 +0000237MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000238{
cristy3ed852e2009-09-05 21:47:34 +0000239 NexusInfo
240 **nexus_info;
241
cristye076a6e2010-08-15 19:59:43 +0000242 register ssize_t
243 i;
244
cristya64b85d2011-09-14 01:02:31 +0000245 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000246 sizeof(*nexus_info));
247 if (nexus_info == (NexusInfo **) NULL)
248 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000249 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
250 sizeof(**nexus_info));
251 if (nexus_info[0] == (NexusInfo *) NULL)
252 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
253 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000254 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000255 {
cristye5f87c82012-02-14 12:44:17 +0000256 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000257 nexus_info[i]->signature=MagickSignature;
258 }
259 return(nexus_info);
260}
261
262/*
263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264% %
265% %
266% %
cristyd43a46b2010-01-21 02:13:41 +0000267+ A c q u i r e P i x e l C a c h e P i x e l s %
268% %
269% %
270% %
271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
272%
273% AcquirePixelCachePixels() returns the pixels associated with the specified
274% image.
275%
276% The format of the AcquirePixelCachePixels() method is:
277%
278% const void *AcquirePixelCachePixels(const Image *image,
279% MagickSizeType *length,ExceptionInfo *exception)
280%
281% A description of each parameter follows:
282%
283% o image: the image.
284%
285% o length: the pixel cache length.
286%
287% o exception: return any errors or warnings in this structure.
288%
289*/
cristyd1dd6e42011-09-04 01:46:08 +0000290MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000291 MagickSizeType *length,ExceptionInfo *exception)
292{
293 CacheInfo
294 *cache_info;
295
296 assert(image != (const Image *) NULL);
297 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000298 assert(exception != (ExceptionInfo *) NULL);
299 assert(exception->signature == MagickSignature);
300 assert(image->cache != (Cache) NULL);
301 cache_info=(CacheInfo *) image->cache;
302 assert(cache_info->signature == MagickSignature);
303 *length=0;
304 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
305 return((const void *) NULL);
306 *length=cache_info->length;
307 return((const void *) cache_info->pixels);
308}
309
310/*
311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312% %
313% %
314% %
cristyf34a1452009-10-24 22:29:27 +0000315+ C a c h e C o m p o n e n t G e n e s i s %
316% %
317% %
318% %
319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320%
321% CacheComponentGenesis() instantiates the cache component.
322%
323% The format of the CacheComponentGenesis method is:
324%
325% MagickBooleanType CacheComponentGenesis(void)
326%
327*/
cristy5ff4eaf2011-09-03 01:38:02 +0000328MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000329{
cristy165b6092009-10-26 13:52:10 +0000330 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000331 return(MagickTrue);
332}
333
334/*
335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336% %
337% %
338% %
339+ C a c h e C o m p o n e n t T e r m i n u s %
340% %
341% %
342% %
343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344%
345% CacheComponentTerminus() destroys the cache component.
346%
347% The format of the CacheComponentTerminus() method is:
348%
349% CacheComponentTerminus(void)
350%
351*/
cristy5ff4eaf2011-09-03 01:38:02 +0000352MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000353{
cristy18b17442009-10-25 18:36:48 +0000354 if (cache_semaphore == (SemaphoreInfo *) NULL)
355 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000356 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000357 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000358 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000359 DestroySemaphoreInfo(&cache_semaphore);
360}
361
362/*
363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364% %
365% %
366% %
cristy3ed852e2009-09-05 21:47:34 +0000367+ C l o n e P i x e l C a c h e %
368% %
369% %
370% %
371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
372%
373% ClonePixelCache() clones a pixel cache.
374%
375% The format of the ClonePixelCache() method is:
376%
377% Cache ClonePixelCache(const Cache cache)
378%
379% A description of each parameter follows:
380%
381% o cache: the pixel cache.
382%
383*/
cristya6577ff2011-09-02 19:54:26 +0000384MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000385{
386 CacheInfo
387 *clone_info;
388
389 const CacheInfo
390 *cache_info;
391
cristy9f027d12011-09-21 01:17:17 +0000392 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000393 cache_info=(const CacheInfo *) cache;
394 assert(cache_info->signature == MagickSignature);
395 if (cache_info->debug != MagickFalse)
396 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
397 cache_info->filename);
398 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
399 if (clone_info == (Cache) NULL)
400 return((Cache) NULL);
401 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
402 return((Cache ) clone_info);
403}
404
405/*
406%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407% %
408% %
409% %
cristy60c44a82009-10-07 00:58:49 +0000410+ 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 +0000411% %
412% %
413% %
414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
415% ClonePixelCachePixels() clones the source pixel cache to the destination
416% cache.
417%
418% The format of the ClonePixelCachePixels() method is:
419%
420% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
421% CacheInfo *source_info,ExceptionInfo *exception)
422%
423% A description of each parameter follows:
424%
425% o cache_info: the pixel cache.
426%
427% o source_info: the source pixel cache.
428%
429% o exception: return any errors or warnings in this structure.
430%
431*/
432
433static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
434{
435 int
436 status;
437
cristy5ee247a2010-02-12 15:42:34 +0000438 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000439 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000440 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000441 {
442 status=close(cache_info->file);
443 cache_info->file=(-1);
444 RelinquishMagickResource(FileResource,1);
445 }
cristyf84a1932010-01-03 18:00:18 +0000446 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000447 return(status == -1 ? MagickFalse : MagickTrue);
448}
449
cristy3ed852e2009-09-05 21:47:34 +0000450static inline MagickSizeType MagickMax(const MagickSizeType x,
451 const MagickSizeType y)
452{
453 if (x > y)
454 return(x);
455 return(y);
456}
457
458static inline MagickSizeType MagickMin(const MagickSizeType x,
459 const MagickSizeType y)
460{
461 if (x < y)
462 return(x);
463 return(y);
464}
465
466static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
467 const MapMode mode)
468{
469 int
470 file;
471
472 /*
473 Open pixel cache on disk.
474 */
cristyf84a1932010-01-03 18:00:18 +0000475 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000476 if (cache_info->file != -1)
477 {
cristyf84a1932010-01-03 18:00:18 +0000478 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000479 return(MagickTrue); /* cache already open */
480 }
cristy3ed852e2009-09-05 21:47:34 +0000481 if (*cache_info->cache_filename == '\0')
482 file=AcquireUniqueFileResource(cache_info->cache_filename);
483 else
484 switch (mode)
485 {
486 case ReadMode:
487 {
cristy18c6c272011-09-23 14:40:37 +0000488 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000489 break;
490 }
491 case WriteMode:
492 {
cristy18c6c272011-09-23 14:40:37 +0000493 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
494 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000495 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000496 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000497 break;
498 }
499 case IOMode:
500 default:
501 {
cristy18c6c272011-09-23 14:40:37 +0000502 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000503 O_EXCL,S_MODE);
504 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000505 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000506 break;
507 }
508 }
509 if (file == -1)
510 {
cristyf84a1932010-01-03 18:00:18 +0000511 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000512 return(MagickFalse);
513 }
514 (void) AcquireMagickResource(FileResource,1);
515 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000516 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000517 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000518 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000519 return(MagickTrue);
520}
521
522static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
523 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000524 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000525{
526 register MagickOffsetType
527 i;
528
529 ssize_t
530 count;
531
cristy08a88202010-03-04 19:18:05 +0000532 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000533#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000534 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000535 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000536 {
cristyf84a1932010-01-03 18:00:18 +0000537 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000538 return((MagickOffsetType) -1);
539 }
540#endif
541 count=0;
542 for (i=0; i < (MagickOffsetType) length; i+=count)
543 {
544#if !defined(MAGICKCORE_HAVE_PREAD)
545 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
546 (MagickSizeType) SSIZE_MAX));
547#else
548 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000549 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000550#endif
551 if (count > 0)
552 continue;
553 count=0;
554 if (errno != EINTR)
555 {
556 i=(-1);
557 break;
558 }
559 }
560#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000561 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000562#endif
563 return(i);
564}
565
566static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
567 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000568 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000569{
570 register MagickOffsetType
571 i;
572
573 ssize_t
574 count;
575
cristy08a88202010-03-04 19:18:05 +0000576 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000577#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000578 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000579 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000580 {
cristyf84a1932010-01-03 18:00:18 +0000581 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000582 return((MagickOffsetType) -1);
583 }
584#endif
585 count=0;
586 for (i=0; i < (MagickOffsetType) length; i+=count)
587 {
588#if !defined(MAGICKCORE_HAVE_PWRITE)
589 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
590 (MagickSizeType) SSIZE_MAX));
591#else
592 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000593 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000594#endif
595 if (count > 0)
596 continue;
597 count=0;
598 if (errno != EINTR)
599 {
600 i=(-1);
601 break;
602 }
603 }
604#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000605 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000606#endif
607 return(i);
608}
609
cristy4c08aed2011-07-01 19:47:50 +0000610static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000611 CacheInfo *cache_info,ExceptionInfo *exception)
612{
613 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000614 count;
cristy3ed852e2009-09-05 21:47:34 +0000615
cristy4c08aed2011-07-01 19:47:50 +0000616 register MagickOffsetType
617 i;
cristye076a6e2010-08-15 19:59:43 +0000618
cristybb503372010-05-27 20:51:26 +0000619 size_t
cristy4c08aed2011-07-01 19:47:50 +0000620 length;
cristy3ed852e2009-09-05 21:47:34 +0000621
cristy4c08aed2011-07-01 19:47:50 +0000622 unsigned char
623 *blob;
624
625 /*
626 Clone pixel cache (both caches on disk).
627 */
cristy3ed852e2009-09-05 21:47:34 +0000628 if (cache_info->debug != MagickFalse)
629 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000630 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000631 sizeof(*blob));
632 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000633 {
cristy4c08aed2011-07-01 19:47:50 +0000634 (void) ThrowMagickException(exception,GetMagickModule(),
635 ResourceLimitError,"MemoryAllocationFailed","`%s'",
636 cache_info->filename);
637 return(MagickFalse);
638 }
cristy3dedf062011-07-02 14:07:40 +0000639 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000640 {
641 blob=(unsigned char *) RelinquishMagickMemory(blob);
642 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
643 cache_info->cache_filename);
644 return(MagickFalse);
645 }
cristy3dedf062011-07-02 14:07:40 +0000646 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000647 {
648 (void) ClosePixelCacheOnDisk(cache_info);
649 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000650 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
651 clone_info->cache_filename);
652 return(MagickFalse);
653 }
cristy4c08aed2011-07-01 19:47:50 +0000654 count=0;
655 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000656 {
cristy4c08aed2011-07-01 19:47:50 +0000657 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
658 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
659 blob);
660 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000661 {
cristy4c08aed2011-07-01 19:47:50 +0000662 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
663 cache_info->cache_filename);
664 break;
cristy3ed852e2009-09-05 21:47:34 +0000665 }
cristy4c08aed2011-07-01 19:47:50 +0000666 length=(size_t) count;
667 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
668 if ((MagickSizeType) count != length)
669 {
670 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
671 clone_info->cache_filename);
672 break;
673 }
674 }
675 (void) ClosePixelCacheOnDisk(clone_info);
676 (void) ClosePixelCacheOnDisk(cache_info);
677 blob=(unsigned char *) RelinquishMagickMemory(blob);
678 if (i < (MagickOffsetType) cache_info->length)
679 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000680 return(MagickTrue);
681}
682
cristyfd24a062012-01-02 14:46:34 +0000683static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000684 CacheInfo *cache_info,ExceptionInfo *exception)
685{
686 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000687 count;
cristy3ed852e2009-09-05 21:47:34 +0000688
cristy4c08aed2011-07-01 19:47:50 +0000689 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000690 {
cristy3ed852e2009-09-05 21:47:34 +0000691 /*
cristy4c08aed2011-07-01 19:47:50 +0000692 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000693 */
cristy4c08aed2011-07-01 19:47:50 +0000694 if (cache_info->debug != MagickFalse)
695 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
696 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
697 cache_info->length);
698 return(MagickTrue);
699 }
700 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
701 {
702 /*
703 Clone pixel cache (one cache on disk, one in memory).
704 */
705 if (cache_info->debug != MagickFalse)
706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
707 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000708 {
cristy4c08aed2011-07-01 19:47:50 +0000709 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000710 cache_info->cache_filename);
711 return(MagickFalse);
712 }
cristy4c08aed2011-07-01 19:47:50 +0000713 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
714 cache_info->length,(unsigned char *) clone_info->pixels);
715 (void) ClosePixelCacheOnDisk(cache_info);
716 if ((MagickSizeType) count != cache_info->length)
717 {
718 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
719 cache_info->cache_filename);
720 return(MagickFalse);
721 }
722 return(MagickTrue);
723 }
724 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
725 {
726 /*
727 Clone pixel cache (one cache on disk, one in memory).
728 */
729 if (clone_info->debug != MagickFalse)
730 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
731 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
732 {
733 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
734 clone_info->cache_filename);
735 return(MagickFalse);
736 }
737 count=WritePixelCacheRegion(clone_info,clone_info->offset,
738 clone_info->length,(unsigned char *) cache_info->pixels);
739 (void) ClosePixelCacheOnDisk(clone_info);
740 if ((MagickSizeType) count != clone_info->length)
741 {
742 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
743 clone_info->cache_filename);
744 return(MagickFalse);
745 }
746 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000747 }
748 /*
cristy4c08aed2011-07-01 19:47:50 +0000749 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000750 */
cristy4c08aed2011-07-01 19:47:50 +0000751 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000752}
753
cristyfd24a062012-01-02 14:46:34 +0000754static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000755 CacheInfo *cache_info,ExceptionInfo *exception)
756{
cristy4c08aed2011-07-01 19:47:50 +0000757 MagickBooleanType
758 status;
cristy3ed852e2009-09-05 21:47:34 +0000759
cristy4c08aed2011-07-01 19:47:50 +0000760 MagickOffsetType
761 cache_offset,
762 clone_offset,
763 count;
764
765 register ssize_t
766 x;
767
cristyfd24a062012-01-02 14:46:34 +0000768 register unsigned char
769 *p;
770
cristy4c08aed2011-07-01 19:47:50 +0000771 size_t
cristy3ed852e2009-09-05 21:47:34 +0000772 length;
773
cristy4c08aed2011-07-01 19:47:50 +0000774 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000775 y;
776
cristy4c08aed2011-07-01 19:47:50 +0000777 unsigned char
778 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000779
cristy4c08aed2011-07-01 19:47:50 +0000780 /*
781 Clone pixel cache (unoptimized).
782 */
cristy3ed852e2009-09-05 21:47:34 +0000783 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000784 {
cristy4c08aed2011-07-01 19:47:50 +0000785 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
787 else
788 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
789 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
790 else
791 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
792 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
793 else
794 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
795 }
cristyed231572011-07-14 02:18:59 +0000796 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
797 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000798 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000799 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000800 if (blob == (unsigned char *) NULL)
801 {
802 (void) ThrowMagickException(exception,GetMagickModule(),
803 ResourceLimitError,"MemoryAllocationFailed","`%s'",
804 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000805 return(MagickFalse);
806 }
cristy4c08aed2011-07-01 19:47:50 +0000807 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
808 cache_offset=0;
809 clone_offset=0;
810 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000811 {
cristy4c08aed2011-07-01 19:47:50 +0000812 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000813 {
cristy4c08aed2011-07-01 19:47:50 +0000814 blob=(unsigned char *) RelinquishMagickMemory(blob);
815 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000816 cache_info->cache_filename);
817 return(MagickFalse);
818 }
cristy4c08aed2011-07-01 19:47:50 +0000819 cache_offset=cache_info->offset;
820 }
821 if (clone_info->type == DiskCache)
822 {
cristy3dedf062011-07-02 14:07:40 +0000823 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000824 {
cristy4c08aed2011-07-01 19:47:50 +0000825 blob=(unsigned char *) RelinquishMagickMemory(blob);
826 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
827 clone_info->cache_filename);
828 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000829 }
cristy4c08aed2011-07-01 19:47:50 +0000830 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000831 }
832 /*
cristy4c08aed2011-07-01 19:47:50 +0000833 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000834 */
cristy4c08aed2011-07-01 19:47:50 +0000835 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000836 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000837 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000838 {
cristy4c08aed2011-07-01 19:47:50 +0000839 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000840 {
cristy9e0719b2011-12-29 03:45:45 +0000841 register ssize_t
842 i;
843
cristy3ed852e2009-09-05 21:47:34 +0000844 /*
cristy4c08aed2011-07-01 19:47:50 +0000845 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000846 */
cristyed231572011-07-14 02:18:59 +0000847 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000848 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000849 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000850 else
851 {
cristyfd24a062012-01-02 14:46:34 +0000852 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000853 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000854 {
cristy4c08aed2011-07-01 19:47:50 +0000855 status=MagickFalse;
856 break;
cristy3ed852e2009-09-05 21:47:34 +0000857 }
858 }
cristy4c08aed2011-07-01 19:47:50 +0000859 cache_offset+=length;
860 if ((y < (ssize_t) clone_info->rows) &&
861 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000862 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000863 {
cristy9e0719b2011-12-29 03:45:45 +0000864 PixelChannel
865 channel;
866
867 PixelTrait
868 traits;
869
870 ssize_t
871 offset;
872
cristy4c08aed2011-07-01 19:47:50 +0000873 /*
cristy3b8fe922011-12-29 18:56:23 +0000874 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000875 */
cristy9e0719b2011-12-29 03:45:45 +0000876 channel=clone_info->channel_map[i].channel;
877 traits=cache_info->channel_map[channel].traits;
878 if (traits == UndefinedPixelTrait)
879 {
cristy0f4425e2011-12-31 20:33:02 +0000880 clone_offset+=sizeof(Quantum);
881 continue;
cristy9e0719b2011-12-29 03:45:45 +0000882 }
cristy0f4425e2011-12-31 20:33:02 +0000883 offset=cache_info->channel_map[channel].offset;
884 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000885 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
886 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000887 else
888 {
cristy0f4425e2011-12-31 20:33:02 +0000889 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000890 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000891 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000892 {
cristy0f4425e2011-12-31 20:33:02 +0000893 status=MagickFalse;
894 break;
cristy4c08aed2011-07-01 19:47:50 +0000895 }
896 }
cristy9e0719b2011-12-29 03:45:45 +0000897 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000898 }
899 }
cristyed231572011-07-14 02:18:59 +0000900 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000901 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
902 for ( ; x < (ssize_t) clone_info->columns; x++)
903 {
904 /*
cristy9e0719b2011-12-29 03:45:45 +0000905 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000906 */
907 if (clone_info->type != DiskCache)
908 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
909 length);
910 else
911 {
912 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
913 if ((MagickSizeType) count != length)
914 {
915 status=MagickFalse;
916 break;
917 }
918 }
919 clone_offset+=length;
920 }
921 }
cristyed231572011-07-14 02:18:59 +0000922 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000923 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
924 for ( ; y < (ssize_t) clone_info->rows; y++)
925 {
926 /*
cristy9e0719b2011-12-29 03:45:45 +0000927 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000928 */
929 for (x=0; x < (ssize_t) clone_info->columns; x++)
930 {
931 if (clone_info->type != DiskCache)
932 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
933 length);
934 else
935 {
936 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
937 if ((MagickSizeType) count != length)
938 {
939 status=MagickFalse;
940 break;
941 }
942 }
943 clone_offset+=length;
944 }
945 }
cristy9e0719b2011-12-29 03:45:45 +0000946 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000947 (clone_info->metacontent_extent != 0))
948 {
949 /*
950 Clone metacontent.
951 */
952 for (y=0; y < (ssize_t) cache_info->rows; y++)
953 {
954 for (x=0; x < (ssize_t) cache_info->columns; x++)
955 {
956 /*
957 Read a set of metacontent.
958 */
959 length=cache_info->metacontent_extent;
960 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000961 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000962 else
963 {
cristyfd24a062012-01-02 14:46:34 +0000964 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000965 if ((MagickSizeType) count != length)
966 {
967 status=MagickFalse;
968 break;
969 }
970 }
971 cache_offset+=length;
972 if ((y < (ssize_t) clone_info->rows) &&
973 (x < (ssize_t) clone_info->columns))
974 {
975 /*
976 Write a set of metacontent.
977 */
978 length=clone_info->metacontent_extent;
979 if (clone_info->type != DiskCache)
980 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000981 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000982 else
983 {
cristyfd24a062012-01-02 14:46:34 +0000984 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000985 if ((MagickSizeType) count != length)
986 {
987 status=MagickFalse;
988 break;
989 }
990 }
991 clone_offset+=length;
992 }
993 }
994 length=clone_info->metacontent_extent;
995 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
996 for ( ; x < (ssize_t) clone_info->columns; x++)
997 {
998 /*
cristy9e0719b2011-12-29 03:45:45 +0000999 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001000 */
1001 if (clone_info->type != DiskCache)
1002 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1003 blob,length);
1004 else
1005 {
cristy208b1002011-08-07 18:51:50 +00001006 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001007 if ((MagickSizeType) count != length)
1008 {
1009 status=MagickFalse;
1010 break;
1011 }
1012 }
1013 clone_offset+=length;
1014 }
1015 }
1016 length=clone_info->metacontent_extent;
1017 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1018 for ( ; y < (ssize_t) clone_info->rows; y++)
1019 {
1020 /*
cristy9e0719b2011-12-29 03:45:45 +00001021 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001022 */
1023 for (x=0; x < (ssize_t) clone_info->columns; x++)
1024 {
1025 if (clone_info->type != DiskCache)
1026 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1027 blob,length);
1028 else
1029 {
1030 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1031 if ((MagickSizeType) count != length)
1032 {
1033 status=MagickFalse;
1034 break;
1035 }
1036 }
1037 clone_offset+=length;
1038 }
1039 }
1040 }
1041 if (clone_info->type == DiskCache)
1042 (void) ClosePixelCacheOnDisk(clone_info);
1043 if (cache_info->type == DiskCache)
1044 (void) ClosePixelCacheOnDisk(cache_info);
1045 blob=(unsigned char *) RelinquishMagickMemory(blob);
1046 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001047}
1048
1049static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1050 CacheInfo *cache_info,ExceptionInfo *exception)
1051{
cristy3dfccb22011-12-28 21:47:20 +00001052 PixelChannelMap
1053 *p,
1054 *q;
1055
cristy5a7fbfb2010-11-06 16:10:59 +00001056 if (cache_info->type == PingCache)
1057 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001058 p=cache_info->channel_map;
1059 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001060 if ((cache_info->columns == clone_info->columns) &&
1061 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001062 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001063 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001064 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001065 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1066 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001067}
1068
1069/*
1070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1071% %
1072% %
1073% %
1074+ C l o n e P i x e l C a c h e M e t h o d s %
1075% %
1076% %
1077% %
1078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079%
1080% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1081% another.
1082%
1083% The format of the ClonePixelCacheMethods() method is:
1084%
1085% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1086%
1087% A description of each parameter follows:
1088%
1089% o clone: Specifies a pointer to a Cache structure.
1090%
1091% o cache: the pixel cache.
1092%
1093*/
cristya6577ff2011-09-02 19:54:26 +00001094MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001095{
1096 CacheInfo
1097 *cache_info,
1098 *source_info;
1099
1100 assert(clone != (Cache) NULL);
1101 source_info=(CacheInfo *) clone;
1102 assert(source_info->signature == MagickSignature);
1103 if (source_info->debug != MagickFalse)
1104 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1105 source_info->filename);
1106 assert(cache != (Cache) NULL);
1107 cache_info=(CacheInfo *) cache;
1108 assert(cache_info->signature == MagickSignature);
1109 source_info->methods=cache_info->methods;
1110}
1111
1112/*
1113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1114% %
1115% %
1116% %
1117+ D e s t r o y I m a g e P i x e l C a c h e %
1118% %
1119% %
1120% %
1121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122%
1123% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1124%
1125% The format of the DestroyImagePixelCache() method is:
1126%
1127% void DestroyImagePixelCache(Image *image)
1128%
1129% A description of each parameter follows:
1130%
1131% o image: the image.
1132%
1133*/
1134static void DestroyImagePixelCache(Image *image)
1135{
1136 assert(image != (Image *) NULL);
1137 assert(image->signature == MagickSignature);
1138 if (image->debug != MagickFalse)
1139 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1140 if (image->cache == (void *) NULL)
1141 return;
1142 image->cache=DestroyPixelCache(image->cache);
1143}
1144
1145/*
1146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1147% %
1148% %
1149% %
1150+ D e s t r o y I m a g e P i x e l s %
1151% %
1152% %
1153% %
1154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1155%
1156% DestroyImagePixels() deallocates memory associated with the pixel cache.
1157%
1158% The format of the DestroyImagePixels() method is:
1159%
1160% void DestroyImagePixels(Image *image)
1161%
1162% A description of each parameter follows:
1163%
1164% o image: the image.
1165%
1166*/
1167MagickExport void DestroyImagePixels(Image *image)
1168{
1169 CacheInfo
1170 *cache_info;
1171
1172 assert(image != (const Image *) NULL);
1173 assert(image->signature == MagickSignature);
1174 if (image->debug != MagickFalse)
1175 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1176 assert(image->cache != (Cache) NULL);
1177 cache_info=(CacheInfo *) image->cache;
1178 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001179 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1180 {
1181 cache_info->methods.destroy_pixel_handler(image);
1182 return;
1183 }
cristy2036f5c2010-09-19 21:18:17 +00001184 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001185}
1186
1187/*
1188%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1189% %
1190% %
1191% %
1192+ D e s t r o y P i x e l C a c h e %
1193% %
1194% %
1195% %
1196%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197%
1198% DestroyPixelCache() deallocates memory associated with the pixel cache.
1199%
1200% The format of the DestroyPixelCache() method is:
1201%
1202% Cache DestroyPixelCache(Cache cache)
1203%
1204% A description of each parameter follows:
1205%
1206% o cache: the pixel cache.
1207%
1208*/
1209
1210static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1211{
1212 switch (cache_info->type)
1213 {
1214 case MemoryCache:
1215 {
1216 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001217 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001218 cache_info->pixels);
1219 else
cristy4c08aed2011-07-01 19:47:50 +00001220 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001221 (size_t) cache_info->length);
1222 RelinquishMagickResource(MemoryResource,cache_info->length);
1223 break;
1224 }
1225 case MapCache:
1226 {
cristy4c08aed2011-07-01 19:47:50 +00001227 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001228 cache_info->length);
1229 RelinquishMagickResource(MapResource,cache_info->length);
1230 }
1231 case DiskCache:
1232 {
1233 if (cache_info->file != -1)
1234 (void) ClosePixelCacheOnDisk(cache_info);
1235 RelinquishMagickResource(DiskResource,cache_info->length);
1236 break;
1237 }
1238 default:
1239 break;
1240 }
1241 cache_info->type=UndefinedCache;
1242 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001243 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001244}
1245
cristya6577ff2011-09-02 19:54:26 +00001246MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001247{
1248 CacheInfo
1249 *cache_info;
1250
cristy3ed852e2009-09-05 21:47:34 +00001251 assert(cache != (Cache) NULL);
1252 cache_info=(CacheInfo *) cache;
1253 assert(cache_info->signature == MagickSignature);
1254 if (cache_info->debug != MagickFalse)
1255 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1256 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001257 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001258 cache_info->reference_count--;
1259 if (cache_info->reference_count != 0)
1260 {
cristyf84a1932010-01-03 18:00:18 +00001261 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001262 return((Cache) NULL);
1263 }
cristyf84a1932010-01-03 18:00:18 +00001264 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001265 if (cache_info->debug != MagickFalse)
1266 {
1267 char
1268 message[MaxTextExtent];
1269
cristyb51dff52011-05-19 16:55:47 +00001270 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001271 cache_info->filename);
1272 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1273 }
cristyc2e1bdd2009-09-10 23:43:34 +00001274 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1275 (cache_info->type != DiskCache)))
1276 RelinquishPixelCachePixels(cache_info);
1277 else
1278 {
1279 RelinquishPixelCachePixels(cache_info);
1280 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1281 }
cristy3ed852e2009-09-05 21:47:34 +00001282 *cache_info->cache_filename='\0';
1283 if (cache_info->nexus_info != (NexusInfo **) NULL)
1284 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1285 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001286 if (cache_info->random_info != (RandomInfo *) NULL)
1287 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001288 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1289 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1290 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1291 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001292 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001293 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001294 cache=(Cache) NULL;
1295 return(cache);
1296}
1297
1298/*
1299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1300% %
1301% %
1302% %
1303+ D e s t r o y P i x e l C a c h e N e x u s %
1304% %
1305% %
1306% %
1307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308%
1309% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1310%
1311% The format of the DestroyPixelCacheNexus() method is:
1312%
1313% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001314% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001315%
1316% A description of each parameter follows:
1317%
1318% o nexus_info: the nexus to destroy.
1319%
1320% o number_threads: the number of nexus threads.
1321%
1322*/
1323
1324static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1325{
1326 if (nexus_info->mapped == MagickFalse)
cristy7dc8ac52012-01-10 20:14:52 +00001327 (void) RelinquishAlignedMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001328 else
1329 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001330 nexus_info->cache=(Quantum *) NULL;
1331 nexus_info->pixels=(Quantum *) NULL;
1332 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001333 nexus_info->length=0;
1334 nexus_info->mapped=MagickFalse;
1335}
1336
cristya6577ff2011-09-02 19:54:26 +00001337MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001338 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001339{
cristybb503372010-05-27 20:51:26 +00001340 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001341 i;
1342
1343 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001344 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001345 {
cristy4c08aed2011-07-01 19:47:50 +00001346 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001347 RelinquishCacheNexusPixels(nexus_info[i]);
1348 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001349 }
cristye5f87c82012-02-14 12:44:17 +00001350 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristyb41ee102010-10-04 16:46:15 +00001351 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001352 return(nexus_info);
1353}
1354
1355/*
1356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1357% %
1358% %
1359% %
cristy4c08aed2011-07-01 19:47:50 +00001360% 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 +00001361% %
1362% %
1363% %
1364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365%
cristy4c08aed2011-07-01 19:47:50 +00001366% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1367% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1368% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001369%
cristy4c08aed2011-07-01 19:47:50 +00001370% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001371%
cristy4c08aed2011-07-01 19:47:50 +00001372% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001373%
1374% A description of each parameter follows:
1375%
1376% o image: the image.
1377%
1378*/
cristy4c08aed2011-07-01 19:47:50 +00001379MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001380{
1381 CacheInfo
1382 *cache_info;
1383
cristy5c9e6f22010-09-17 17:31:01 +00001384 const int
1385 id = GetOpenMPThreadId();
1386
cristy4c08aed2011-07-01 19:47:50 +00001387 void
1388 *metacontent;
1389
cristye7cc7cf2010-09-21 13:26:47 +00001390 assert(image != (const Image *) NULL);
1391 assert(image->signature == MagickSignature);
1392 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001393 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001394 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001395 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1396 (GetAuthenticMetacontentFromHandler) NULL)
1397 {
1398 metacontent=cache_info->methods.
1399 get_authentic_metacontent_from_handler(image);
1400 return(metacontent);
1401 }
cristy6ebe97c2010-07-03 01:17:28 +00001402 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001403 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1404 cache_info->nexus_info[id]);
1405 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001406}
1407
1408/*
1409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410% %
1411% %
1412% %
cristy4c08aed2011-07-01 19:47:50 +00001413+ 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 +00001414% %
1415% %
1416% %
1417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1418%
cristy4c08aed2011-07-01 19:47:50 +00001419% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1420% with the last call to QueueAuthenticPixelsCache() or
1421% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001422%
cristy4c08aed2011-07-01 19:47:50 +00001423% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001424%
cristy4c08aed2011-07-01 19:47:50 +00001425% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001426%
1427% A description of each parameter follows:
1428%
1429% o image: the image.
1430%
1431*/
cristy4c08aed2011-07-01 19:47:50 +00001432static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001433{
1434 CacheInfo
1435 *cache_info;
1436
cristy2036f5c2010-09-19 21:18:17 +00001437 const int
1438 id = GetOpenMPThreadId();
1439
cristy4c08aed2011-07-01 19:47:50 +00001440 void
1441 *metacontent;
1442
cristy3ed852e2009-09-05 21:47:34 +00001443 assert(image != (const Image *) NULL);
1444 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001445 assert(image->cache != (Cache) NULL);
1446 cache_info=(CacheInfo *) image->cache;
1447 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001448 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001449 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1450 cache_info->nexus_info[id]);
1451 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001452}
1453
1454/*
1455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1456% %
1457% %
1458% %
1459+ 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 %
1460% %
1461% %
1462% %
1463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1464%
1465% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1466% disk pixel cache as defined by the geometry parameters. A pointer to the
1467% pixels is returned if the pixels are transferred, otherwise a NULL is
1468% returned.
1469%
1470% The format of the GetAuthenticPixelCacheNexus() method is:
1471%
cristy4c08aed2011-07-01 19:47:50 +00001472% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001473% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001474% NexusInfo *nexus_info,ExceptionInfo *exception)
1475%
1476% A description of each parameter follows:
1477%
1478% o image: the image.
1479%
1480% o x,y,columns,rows: These values define the perimeter of a region of
1481% pixels.
1482%
1483% o nexus_info: the cache nexus to return.
1484%
1485% o exception: return any errors or warnings in this structure.
1486%
1487*/
1488
cristy4c08aed2011-07-01 19:47:50 +00001489static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001490 NexusInfo *nexus_info)
1491{
cristy4c08aed2011-07-01 19:47:50 +00001492 MagickBooleanType
1493 status;
1494
cristy3ed852e2009-09-05 21:47:34 +00001495 MagickOffsetType
1496 offset;
1497
cristy73724512010-04-12 14:43:14 +00001498 if (cache_info->type == PingCache)
1499 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001500 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1501 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001502 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001503 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001504 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001505}
1506
cristya6577ff2011-09-02 19:54:26 +00001507MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001508 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001509 NexusInfo *nexus_info,ExceptionInfo *exception)
1510{
1511 CacheInfo
1512 *cache_info;
1513
cristy4c08aed2011-07-01 19:47:50 +00001514 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001515 *q;
cristy3ed852e2009-09-05 21:47:34 +00001516
1517 /*
1518 Transfer pixels from the cache.
1519 */
1520 assert(image != (Image *) NULL);
1521 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001522 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1523 exception);
cristyacd2ed22011-08-30 01:44:23 +00001524 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001525 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001526 cache_info=(CacheInfo *) image->cache;
1527 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001528 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001529 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001530 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001531 return((Quantum *) NULL);
1532 if (cache_info->metacontent_extent != 0)
1533 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1534 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001535 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001536}
1537
1538/*
1539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540% %
1541% %
1542% %
1543+ 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 %
1544% %
1545% %
1546% %
1547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1548%
1549% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1550% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1551%
1552% The format of the GetAuthenticPixelsFromCache() method is:
1553%
cristy4c08aed2011-07-01 19:47:50 +00001554% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001555%
1556% A description of each parameter follows:
1557%
1558% o image: the image.
1559%
1560*/
cristy4c08aed2011-07-01 19:47:50 +00001561static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001562{
1563 CacheInfo
1564 *cache_info;
1565
cristy5c9e6f22010-09-17 17:31:01 +00001566 const int
1567 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001568
cristye7cc7cf2010-09-21 13:26:47 +00001569 assert(image != (const Image *) NULL);
1570 assert(image->signature == MagickSignature);
1571 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001572 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001573 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001574 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001575 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001576}
1577
1578/*
1579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1580% %
1581% %
1582% %
1583% G e t A u t h e n t i c P i x e l Q u e u e %
1584% %
1585% %
1586% %
1587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588%
cristy4c08aed2011-07-01 19:47:50 +00001589% GetAuthenticPixelQueue() returns the authentic pixels associated
1590% corresponding with the last call to QueueAuthenticPixels() or
1591% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001592%
1593% The format of the GetAuthenticPixelQueue() method is:
1594%
cristy4c08aed2011-07-01 19:47:50 +00001595% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001596%
1597% A description of each parameter follows:
1598%
1599% o image: the image.
1600%
1601*/
cristy4c08aed2011-07-01 19:47:50 +00001602MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001603{
1604 CacheInfo
1605 *cache_info;
1606
cristy2036f5c2010-09-19 21:18:17 +00001607 const int
1608 id = GetOpenMPThreadId();
1609
cristy3ed852e2009-09-05 21:47:34 +00001610 assert(image != (const Image *) NULL);
1611 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001612 assert(image->cache != (Cache) NULL);
1613 cache_info=(CacheInfo *) image->cache;
1614 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001615 if (cache_info->methods.get_authentic_pixels_from_handler !=
1616 (GetAuthenticPixelsFromHandler) NULL)
1617 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001618 assert(id < (int) cache_info->number_threads);
1619 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001620}
1621
1622/*
1623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624% %
1625% %
1626% %
1627% G e t A u t h e n t i c P i x e l s %
1628% %
1629% %
cristy4c08aed2011-07-01 19:47:50 +00001630% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001631%
1632% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001633% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001634% representing the region is returned, otherwise NULL is returned.
1635%
1636% The returned pointer may point to a temporary working copy of the pixels
1637% or it may point to the original pixels in memory. Performance is maximized
1638% if the selected region is part of one row, or one or more full rows, since
1639% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001640% if the image is in memory, or in a memory-mapped file. The returned pointer
1641% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001642%
1643% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001644% Quantum. If the image has corresponding metacontent,call
1645% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1646% meta-content corresponding to the region. Once the Quantum array has
1647% been updated, the changes must be saved back to the underlying image using
1648% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001649%
1650% The format of the GetAuthenticPixels() method is:
1651%
cristy4c08aed2011-07-01 19:47:50 +00001652% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001653% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001654% ExceptionInfo *exception)
1655%
1656% A description of each parameter follows:
1657%
1658% o image: the image.
1659%
1660% o x,y,columns,rows: These values define the perimeter of a region of
1661% pixels.
1662%
1663% o exception: return any errors or warnings in this structure.
1664%
1665*/
cristy4c08aed2011-07-01 19:47:50 +00001666MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001667 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001668 ExceptionInfo *exception)
1669{
1670 CacheInfo
1671 *cache_info;
1672
cristy2036f5c2010-09-19 21:18:17 +00001673 const int
1674 id = GetOpenMPThreadId();
1675
cristy4c08aed2011-07-01 19:47:50 +00001676 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001677 *q;
cristy4c08aed2011-07-01 19:47:50 +00001678
cristy3ed852e2009-09-05 21:47:34 +00001679 assert(image != (Image *) NULL);
1680 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001681 assert(image->cache != (Cache) NULL);
1682 cache_info=(CacheInfo *) image->cache;
1683 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001684 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001685 (GetAuthenticPixelsHandler) NULL)
1686 {
cristyacd2ed22011-08-30 01:44:23 +00001687 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1688 exception);
1689 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001690 }
cristy2036f5c2010-09-19 21:18:17 +00001691 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001692 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001693 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001694 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001695}
1696
1697/*
1698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1699% %
1700% %
1701% %
1702+ G e t A u t h e n t i c P i x e l s C a c h e %
1703% %
1704% %
1705% %
1706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1707%
1708% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1709% as defined by the geometry parameters. A pointer to the pixels is returned
1710% if the pixels are transferred, otherwise a NULL is returned.
1711%
1712% The format of the GetAuthenticPixelsCache() method is:
1713%
cristy4c08aed2011-07-01 19:47:50 +00001714% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001715% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001716% ExceptionInfo *exception)
1717%
1718% A description of each parameter follows:
1719%
1720% o image: the image.
1721%
1722% o x,y,columns,rows: These values define the perimeter of a region of
1723% pixels.
1724%
1725% o exception: return any errors or warnings in this structure.
1726%
1727*/
cristy4c08aed2011-07-01 19:47:50 +00001728static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001729 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001730 ExceptionInfo *exception)
1731{
1732 CacheInfo
1733 *cache_info;
1734
cristy5c9e6f22010-09-17 17:31:01 +00001735 const int
1736 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001737
cristy4c08aed2011-07-01 19:47:50 +00001738 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001739 *q;
cristy4c08aed2011-07-01 19:47:50 +00001740
cristye7cc7cf2010-09-21 13:26:47 +00001741 assert(image != (const Image *) NULL);
1742 assert(image->signature == MagickSignature);
1743 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001744 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001745 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001746 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001747 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001748 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001749 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001750 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001751 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001752}
1753
1754/*
1755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1756% %
1757% %
1758% %
1759+ G e t I m a g e E x t e n t %
1760% %
1761% %
1762% %
1763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1764%
cristy4c08aed2011-07-01 19:47:50 +00001765% GetImageExtent() returns the extent of the pixels associated corresponding
1766% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001767%
1768% The format of the GetImageExtent() method is:
1769%
1770% MagickSizeType GetImageExtent(const Image *image)
1771%
1772% A description of each parameter follows:
1773%
1774% o image: the image.
1775%
1776*/
1777MagickExport MagickSizeType GetImageExtent(const Image *image)
1778{
1779 CacheInfo
1780 *cache_info;
1781
cristy5c9e6f22010-09-17 17:31:01 +00001782 const int
1783 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001784
cristy3ed852e2009-09-05 21:47:34 +00001785 assert(image != (Image *) NULL);
1786 assert(image->signature == MagickSignature);
1787 if (image->debug != MagickFalse)
1788 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1789 assert(image->cache != (Cache) NULL);
1790 cache_info=(CacheInfo *) image->cache;
1791 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001792 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001793 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001794}
1795
1796/*
1797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1798% %
1799% %
1800% %
1801+ G e t I m a g e P i x e l C a c h e %
1802% %
1803% %
1804% %
1805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1806%
1807% GetImagePixelCache() ensures that there is only a single reference to the
1808% pixel cache to be modified, updating the provided cache pointer to point to
1809% a clone of the original pixel cache if necessary.
1810%
1811% The format of the GetImagePixelCache method is:
1812%
1813% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1814% ExceptionInfo *exception)
1815%
1816% A description of each parameter follows:
1817%
1818% o image: the image.
1819%
1820% o clone: any value other than MagickFalse clones the cache pixels.
1821%
1822% o exception: return any errors or warnings in this structure.
1823%
1824*/
cristyaf894d72011-08-06 23:03:10 +00001825
cristy3ed852e2009-09-05 21:47:34 +00001826static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1827{
1828 CacheInfo
1829 *cache_info;
1830
cristy9e0719b2011-12-29 03:45:45 +00001831 PixelChannelMap
1832 *p,
1833 *q;
1834
cristy3ed852e2009-09-05 21:47:34 +00001835 /*
1836 Does the image match the pixel cache morphology?
1837 */
1838 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001839 p=image->channel_map;
1840 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001841 if ((image->storage_class != cache_info->storage_class) ||
1842 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001843 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001844 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001845 (image->columns != cache_info->columns) ||
1846 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001847 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001848 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001849 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001850 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1851 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1852 return(MagickFalse);
1853 return(MagickTrue);
1854}
1855
cristycd01fae2011-08-06 23:52:42 +00001856static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1857 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001858{
1859 CacheInfo
1860 *cache_info;
1861
cristy3ed852e2009-09-05 21:47:34 +00001862 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001863 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001864 status;
1865
cristy50a10922010-02-15 18:35:25 +00001866 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001867 cpu_throttle = 0,
1868 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001869 time_limit = 0;
1870
cristy1ea34962010-07-01 19:49:21 +00001871 static time_t
cristy208b1002011-08-07 18:51:50 +00001872 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001873
cristyc4f9f132010-03-04 18:50:01 +00001874 status=MagickTrue;
1875 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001876 if (cpu_throttle == 0)
1877 {
1878 char
1879 *limit;
1880
1881 /*
1882 Set CPU throttle in milleseconds.
1883 */
1884 cpu_throttle=MagickResourceInfinity;
1885 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1886 if (limit == (char *) NULL)
1887 limit=GetPolicyValue("throttle");
1888 if (limit != (char *) NULL)
1889 {
1890 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1891 limit=DestroyString(limit);
1892 }
1893 }
1894 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1895 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001896 if (time_limit == 0)
1897 {
cristy6ebe97c2010-07-03 01:17:28 +00001898 /*
1899 Set the exire time in seconds.
1900 */
cristy1ea34962010-07-01 19:49:21 +00001901 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001902 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001903 }
1904 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001905 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001906 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001907 assert(image->cache != (Cache) NULL);
1908 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001909 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001910 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001911 {
cristyceb55ee2010-11-06 16:05:49 +00001912 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001913 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001914 {
cristyceb55ee2010-11-06 16:05:49 +00001915 Image
1916 clone_image;
1917
1918 CacheInfo
1919 *clone_info;
1920
1921 /*
1922 Clone pixel cache.
1923 */
1924 clone_image=(*image);
1925 clone_image.semaphore=AllocateSemaphoreInfo();
1926 clone_image.reference_count=1;
1927 clone_image.cache=ClonePixelCache(cache_info);
1928 clone_info=(CacheInfo *) clone_image.cache;
1929 status=OpenPixelCache(&clone_image,IOMode,exception);
1930 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001931 {
cristy5a7fbfb2010-11-06 16:10:59 +00001932 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001933 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001934 if (status != MagickFalse)
1935 {
cristy979bf772011-08-08 00:04:15 +00001936 if (cache_info->mode == ReadMode)
1937 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001938 destroy=MagickTrue;
1939 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001940 }
1941 }
cristyceb55ee2010-11-06 16:05:49 +00001942 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001943 }
cristyceb55ee2010-11-06 16:05:49 +00001944 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001945 }
cristy4320e0e2009-09-10 15:00:08 +00001946 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001947 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001948 if (status != MagickFalse)
1949 {
1950 /*
1951 Ensure the image matches the pixel cache morphology.
1952 */
1953 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001954 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001955 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001956 {
1957 status=OpenPixelCache(image,IOMode,exception);
1958 cache_info=(CacheInfo *) image->cache;
1959 if (cache_info->type == DiskCache)
1960 (void) ClosePixelCacheOnDisk(cache_info);
1961 }
cristy3ed852e2009-09-05 21:47:34 +00001962 }
cristyf84a1932010-01-03 18:00:18 +00001963 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001964 if (status == MagickFalse)
1965 return((Cache) NULL);
1966 return(image->cache);
1967}
1968
1969/*
1970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1971% %
1972% %
1973% %
1974% G e t O n e A u t h e n t i c P i x e l %
1975% %
1976% %
1977% %
1978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1979%
1980% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1981% location. The image background color is returned if an error occurs.
1982%
1983% The format of the GetOneAuthenticPixel() method is:
1984%
cristybb503372010-05-27 20:51:26 +00001985% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00001986% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001987%
1988% A description of each parameter follows:
1989%
1990% o image: the image.
1991%
1992% o x,y: These values define the location of the pixel to return.
1993%
1994% o pixel: return a pixel at the specified (x,y) location.
1995%
1996% o exception: return any errors or warnings in this structure.
1997%
1998*/
cristyacbbb7c2010-06-30 18:56:48 +00001999MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002000 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002001{
2002 CacheInfo
2003 *cache_info;
2004
cristy4c08aed2011-07-01 19:47:50 +00002005 register Quantum
2006 *q;
cristy2036f5c2010-09-19 21:18:17 +00002007
cristy2ed42f62011-10-02 19:49:57 +00002008 register ssize_t
2009 i;
2010
cristy3ed852e2009-09-05 21:47:34 +00002011 assert(image != (Image *) NULL);
2012 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002013 assert(image->cache != (Cache) NULL);
2014 cache_info=(CacheInfo *) image->cache;
2015 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002016 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002017 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2018 (GetOneAuthenticPixelFromHandler) NULL)
2019 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2020 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002021 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2022 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002023 {
cristy9e0719b2011-12-29 03:45:45 +00002024 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2025 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2026 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2027 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2028 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002029 return(MagickFalse);
2030 }
2031 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2032 {
2033 PixelChannel
2034 channel;
2035
cristye2a912b2011-12-05 20:02:07 +00002036 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002037 pixel[channel]=q[i];
2038 }
cristy2036f5c2010-09-19 21:18:17 +00002039 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002040}
2041
2042/*
2043%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2044% %
2045% %
2046% %
2047+ 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 %
2048% %
2049% %
2050% %
2051%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2052%
2053% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2054% location. The image background color is returned if an error occurs.
2055%
2056% The format of the GetOneAuthenticPixelFromCache() method is:
2057%
2058% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002059% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002060% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002061%
2062% A description of each parameter follows:
2063%
2064% o image: the image.
2065%
2066% o x,y: These values define the location of the pixel to return.
2067%
2068% o pixel: return a pixel at the specified (x,y) location.
2069%
2070% o exception: return any errors or warnings in this structure.
2071%
2072*/
2073static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002074 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002075{
cristy098f78c2010-09-23 17:28:44 +00002076 CacheInfo
2077 *cache_info;
2078
2079 const int
2080 id = GetOpenMPThreadId();
2081
cristy4c08aed2011-07-01 19:47:50 +00002082 register Quantum
2083 *q;
cristy3ed852e2009-09-05 21:47:34 +00002084
cristy2ed42f62011-10-02 19:49:57 +00002085 register ssize_t
2086 i;
2087
cristy0158a4b2010-09-20 13:59:45 +00002088 assert(image != (const Image *) NULL);
2089 assert(image->signature == MagickSignature);
2090 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002091 cache_info=(CacheInfo *) image->cache;
2092 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002093 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002094 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002095 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2096 exception);
2097 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002098 {
cristy9e0719b2011-12-29 03:45:45 +00002099 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2100 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2101 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2102 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2103 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002104 return(MagickFalse);
2105 }
2106 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2107 {
2108 PixelChannel
2109 channel;
2110
cristye2a912b2011-12-05 20:02:07 +00002111 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002112 pixel[channel]=q[i];
2113 }
cristy3ed852e2009-09-05 21:47:34 +00002114 return(MagickTrue);
2115}
2116
2117/*
2118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2119% %
2120% %
2121% %
cristy3ed852e2009-09-05 21:47:34 +00002122% G e t O n e V i r t u a l P i x e l %
2123% %
2124% %
2125% %
2126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2127%
2128% GetOneVirtualPixel() returns a single virtual pixel at the specified
2129% (x,y) location. The image background color is returned if an error occurs.
2130% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2131%
2132% The format of the GetOneVirtualPixel() method is:
2133%
cristybb503372010-05-27 20:51:26 +00002134% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002135% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002136%
2137% A description of each parameter follows:
2138%
2139% o image: the image.
2140%
2141% o x,y: These values define the location of the pixel to return.
2142%
2143% o pixel: return a pixel at the specified (x,y) location.
2144%
2145% o exception: return any errors or warnings in this structure.
2146%
2147*/
2148MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002149 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002150{
cristy3ed852e2009-09-05 21:47:34 +00002151 CacheInfo
2152 *cache_info;
2153
cristy0158a4b2010-09-20 13:59:45 +00002154 const int
2155 id = GetOpenMPThreadId();
2156
cristy4c08aed2011-07-01 19:47:50 +00002157 const Quantum
2158 *p;
cristy2036f5c2010-09-19 21:18:17 +00002159
cristy2ed42f62011-10-02 19:49:57 +00002160 register ssize_t
2161 i;
2162
cristy3ed852e2009-09-05 21:47:34 +00002163 assert(image != (const Image *) NULL);
2164 assert(image->signature == MagickSignature);
2165 assert(image->cache != (Cache) NULL);
2166 cache_info=(CacheInfo *) image->cache;
2167 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002168 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002169 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2170 (GetOneVirtualPixelFromHandler) NULL)
2171 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2172 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002173 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002174 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002175 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002176 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002177 {
cristy9e0719b2011-12-29 03:45:45 +00002178 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2179 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2180 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2181 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2182 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002183 return(MagickFalse);
2184 }
2185 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2186 {
2187 PixelChannel
2188 channel;
2189
cristye2a912b2011-12-05 20:02:07 +00002190 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002191 pixel[channel]=p[i];
2192 }
cristy2036f5c2010-09-19 21:18:17 +00002193 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002194}
2195
2196/*
2197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2198% %
2199% %
2200% %
2201+ 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 %
2202% %
2203% %
2204% %
2205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2206%
2207% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2208% specified (x,y) location. The image background color is returned if an
2209% error occurs.
2210%
2211% The format of the GetOneVirtualPixelFromCache() method is:
2212%
2213% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002214% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002215% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002216%
2217% A description of each parameter follows:
2218%
2219% o image: the image.
2220%
2221% o virtual_pixel_method: the virtual pixel method.
2222%
2223% o x,y: These values define the location of the pixel to return.
2224%
2225% o pixel: return a pixel at the specified (x,y) location.
2226%
2227% o exception: return any errors or warnings in this structure.
2228%
2229*/
2230static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002231 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002232 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002233{
cristy0158a4b2010-09-20 13:59:45 +00002234 CacheInfo
2235 *cache_info;
2236
2237 const int
2238 id = GetOpenMPThreadId();
2239
cristy4c08aed2011-07-01 19:47:50 +00002240 const Quantum
2241 *p;
cristy3ed852e2009-09-05 21:47:34 +00002242
cristy2ed42f62011-10-02 19:49:57 +00002243 register ssize_t
2244 i;
2245
cristye7cc7cf2010-09-21 13:26:47 +00002246 assert(image != (const Image *) NULL);
2247 assert(image->signature == MagickSignature);
2248 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002249 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002250 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002251 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002252 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002253 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002254 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002255 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002256 {
cristy9e0719b2011-12-29 03:45:45 +00002257 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2258 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2259 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2260 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2261 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002262 return(MagickFalse);
2263 }
2264 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2265 {
2266 PixelChannel
2267 channel;
2268
cristye2a912b2011-12-05 20:02:07 +00002269 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002270 pixel[channel]=p[i];
2271 }
cristy3ed852e2009-09-05 21:47:34 +00002272 return(MagickTrue);
2273}
2274
2275/*
2276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2277% %
2278% %
2279% %
cristy3aa93752011-12-18 15:54:24 +00002280% G e t O n e V i r t u a l P i x e l I n f o %
2281% %
2282% %
2283% %
2284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285%
2286% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2287% location. The image background color is returned if an error occurs. If
2288% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2289%
2290% The format of the GetOneVirtualPixelInfo() method is:
2291%
2292% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2293% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2294% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2295%
2296% A description of each parameter follows:
2297%
2298% o image: the image.
2299%
2300% o virtual_pixel_method: the virtual pixel method.
2301%
2302% o x,y: these values define the location of the pixel to return.
2303%
2304% o pixel: return a pixel at the specified (x,y) location.
2305%
2306% o exception: return any errors or warnings in this structure.
2307%
2308*/
2309MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2310 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2311 PixelInfo *pixel,ExceptionInfo *exception)
2312{
2313 CacheInfo
2314 *cache_info;
2315
2316 const int
2317 id = GetOpenMPThreadId();
2318
2319 register const Quantum
2320 *p;
2321
2322 assert(image != (const Image *) NULL);
2323 assert(image->signature == MagickSignature);
2324 assert(image->cache != (Cache) NULL);
2325 cache_info=(CacheInfo *) image->cache;
2326 assert(cache_info->signature == MagickSignature);
2327 assert(id < (int) cache_info->number_threads);
2328 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2329 cache_info->nexus_info[id],exception);
2330 GetPixelInfo(image,pixel);
2331 if (p == (const Quantum *) NULL)
2332 return(MagickFalse);
2333 GetPixelInfoPixel(image,p,pixel);
2334 return(MagickTrue);
2335}
2336
2337/*
2338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2339% %
2340% %
2341% %
cristy3ed852e2009-09-05 21:47:34 +00002342+ G e t P i x e l C a c h e C o l o r s p a c e %
2343% %
2344% %
2345% %
2346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2347%
2348% GetPixelCacheColorspace() returns the class type of the pixel cache.
2349%
2350% The format of the GetPixelCacheColorspace() method is:
2351%
2352% Colorspace GetPixelCacheColorspace(Cache cache)
2353%
2354% A description of each parameter follows:
2355%
2356% o cache: the pixel cache.
2357%
2358*/
cristya6577ff2011-09-02 19:54:26 +00002359MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002360{
2361 CacheInfo
2362 *cache_info;
2363
2364 assert(cache != (Cache) NULL);
2365 cache_info=(CacheInfo *) cache;
2366 assert(cache_info->signature == MagickSignature);
2367 if (cache_info->debug != MagickFalse)
2368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2369 cache_info->filename);
2370 return(cache_info->colorspace);
2371}
2372
2373/*
2374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2375% %
2376% %
2377% %
2378+ G e t P i x e l C a c h e M e t h o d s %
2379% %
2380% %
2381% %
2382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2383%
2384% GetPixelCacheMethods() initializes the CacheMethods structure.
2385%
2386% The format of the GetPixelCacheMethods() method is:
2387%
2388% void GetPixelCacheMethods(CacheMethods *cache_methods)
2389%
2390% A description of each parameter follows:
2391%
2392% o cache_methods: Specifies a pointer to a CacheMethods structure.
2393%
2394*/
cristya6577ff2011-09-02 19:54:26 +00002395MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002396{
2397 assert(cache_methods != (CacheMethods *) NULL);
2398 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2399 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2400 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002401 cache_methods->get_virtual_metacontent_from_handler=
2402 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002403 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2404 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002405 cache_methods->get_authentic_metacontent_from_handler=
2406 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002407 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2408 cache_methods->get_one_authentic_pixel_from_handler=
2409 GetOneAuthenticPixelFromCache;
2410 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2411 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2412 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2413}
2414
2415/*
2416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2417% %
2418% %
2419% %
2420+ G e t P i x e l C a c h e N e x u s E x t e n t %
2421% %
2422% %
2423% %
2424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2425%
cristy4c08aed2011-07-01 19:47:50 +00002426% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2427% corresponding with the last call to SetPixelCacheNexusPixels() or
2428% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002429%
2430% The format of the GetPixelCacheNexusExtent() method is:
2431%
2432% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2433% NexusInfo *nexus_info)
2434%
2435% A description of each parameter follows:
2436%
2437% o nexus_info: the nexus info.
2438%
2439*/
cristya6577ff2011-09-02 19:54:26 +00002440MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002441 NexusInfo *nexus_info)
2442{
2443 CacheInfo
2444 *cache_info;
2445
2446 MagickSizeType
2447 extent;
2448
cristy9f027d12011-09-21 01:17:17 +00002449 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002450 cache_info=(CacheInfo *) cache;
2451 assert(cache_info->signature == MagickSignature);
2452 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2453 if (extent == 0)
2454 return((MagickSizeType) cache_info->columns*cache_info->rows);
2455 return(extent);
2456}
2457
2458/*
2459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2460% %
2461% %
2462% %
cristy4c08aed2011-07-01 19:47:50 +00002463+ 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 +00002464% %
2465% %
2466% %
2467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2468%
cristy4c08aed2011-07-01 19:47:50 +00002469% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2470% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002471%
cristy4c08aed2011-07-01 19:47:50 +00002472% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002473%
cristy4c08aed2011-07-01 19:47:50 +00002474% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002475% NexusInfo *nexus_info)
2476%
2477% A description of each parameter follows:
2478%
2479% o cache: the pixel cache.
2480%
cristy4c08aed2011-07-01 19:47:50 +00002481% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002482%
2483*/
cristya6577ff2011-09-02 19:54:26 +00002484MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002485 NexusInfo *nexus_info)
2486{
2487 CacheInfo
2488 *cache_info;
2489
cristy9f027d12011-09-21 01:17:17 +00002490 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002491 cache_info=(CacheInfo *) cache;
2492 assert(cache_info->signature == MagickSignature);
2493 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002494 return((void *) NULL);
2495 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002496}
2497
2498/*
2499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2500% %
2501% %
2502% %
2503+ G e t P i x e l C a c h e N e x u s P i x e l s %
2504% %
2505% %
2506% %
2507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508%
2509% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2510% cache nexus.
2511%
2512% The format of the GetPixelCacheNexusPixels() method is:
2513%
cristy4c08aed2011-07-01 19:47:50 +00002514% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002515% NexusInfo *nexus_info)
2516%
2517% A description of each parameter follows:
2518%
2519% o cache: the pixel cache.
2520%
2521% o nexus_info: the cache nexus to return the pixels.
2522%
2523*/
cristya6577ff2011-09-02 19:54:26 +00002524MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002525 NexusInfo *nexus_info)
2526{
2527 CacheInfo
2528 *cache_info;
2529
cristy9f027d12011-09-21 01:17:17 +00002530 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002531 cache_info=(CacheInfo *) cache;
2532 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002533 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002534 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002535 return(nexus_info->pixels);
2536}
2537
2538/*
2539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2540% %
2541% %
2542% %
cristy056ba772010-01-02 23:33:54 +00002543+ G e t P i x e l C a c h e P i x e l s %
2544% %
2545% %
2546% %
2547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548%
2549% GetPixelCachePixels() returns the pixels associated with the specified image.
2550%
2551% The format of the GetPixelCachePixels() method is:
2552%
cristyf84a1932010-01-03 18:00:18 +00002553% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2554% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002555%
2556% A description of each parameter follows:
2557%
2558% o image: the image.
2559%
2560% o length: the pixel cache length.
2561%
cristyf84a1932010-01-03 18:00:18 +00002562% o exception: return any errors or warnings in this structure.
2563%
cristy056ba772010-01-02 23:33:54 +00002564*/
cristyd1dd6e42011-09-04 01:46:08 +00002565MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002566 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002567{
2568 CacheInfo
2569 *cache_info;
2570
2571 assert(image != (const Image *) NULL);
2572 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002573 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002574 assert(length != (MagickSizeType *) NULL);
2575 assert(exception != (ExceptionInfo *) NULL);
2576 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002577 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002578 assert(cache_info->signature == MagickSignature);
2579 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002580 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002581 return((void *) NULL);
2582 *length=cache_info->length;
2583 return((void *) cache_info->pixels);
2584}
2585
2586/*
2587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2588% %
2589% %
2590% %
cristyb32b90a2009-09-07 21:45:48 +00002591+ 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 +00002592% %
2593% %
2594% %
2595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2596%
2597% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2598%
2599% The format of the GetPixelCacheStorageClass() method is:
2600%
2601% ClassType GetPixelCacheStorageClass(Cache cache)
2602%
2603% A description of each parameter follows:
2604%
2605% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2606%
2607% o cache: the pixel cache.
2608%
2609*/
cristya6577ff2011-09-02 19:54:26 +00002610MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002611{
2612 CacheInfo
2613 *cache_info;
2614
2615 assert(cache != (Cache) NULL);
2616 cache_info=(CacheInfo *) cache;
2617 assert(cache_info->signature == MagickSignature);
2618 if (cache_info->debug != MagickFalse)
2619 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2620 cache_info->filename);
2621 return(cache_info->storage_class);
2622}
2623
2624/*
2625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2626% %
2627% %
2628% %
cristyb32b90a2009-09-07 21:45:48 +00002629+ G e t P i x e l C a c h e T i l e S i z e %
2630% %
2631% %
2632% %
2633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2634%
2635% GetPixelCacheTileSize() returns the pixel cache tile size.
2636%
2637% The format of the GetPixelCacheTileSize() method is:
2638%
cristybb503372010-05-27 20:51:26 +00002639% void GetPixelCacheTileSize(const Image *image,size_t *width,
2640% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002641%
2642% A description of each parameter follows:
2643%
2644% o image: the image.
2645%
2646% o width: the optimize cache tile width in pixels.
2647%
2648% o height: the optimize cache tile height in pixels.
2649%
2650*/
cristya6577ff2011-09-02 19:54:26 +00002651MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002652 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002653{
cristy4c08aed2011-07-01 19:47:50 +00002654 CacheInfo
2655 *cache_info;
2656
cristyb32b90a2009-09-07 21:45:48 +00002657 assert(image != (Image *) NULL);
2658 assert(image->signature == MagickSignature);
2659 if (image->debug != MagickFalse)
2660 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002661 cache_info=(CacheInfo *) image->cache;
2662 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002663 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002664 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002665 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002666 *height=(*width);
2667}
2668
2669/*
2670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671% %
2672% %
2673% %
2674+ G e t P i x e l C a c h e T y p e %
2675% %
2676% %
2677% %
2678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2679%
2680% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2681%
2682% The format of the GetPixelCacheType() method is:
2683%
2684% CacheType GetPixelCacheType(const Image *image)
2685%
2686% A description of each parameter follows:
2687%
2688% o image: the image.
2689%
2690*/
cristya6577ff2011-09-02 19:54:26 +00002691MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002692{
2693 CacheInfo
2694 *cache_info;
2695
2696 assert(image != (Image *) NULL);
2697 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002698 assert(image->cache != (Cache) NULL);
2699 cache_info=(CacheInfo *) image->cache;
2700 assert(cache_info->signature == MagickSignature);
2701 return(cache_info->type);
2702}
2703
2704/*
2705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2706% %
2707% %
2708% %
cristy3ed852e2009-09-05 21:47:34 +00002709+ 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 %
2710% %
2711% %
2712% %
2713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714%
2715% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2716% pixel cache. A virtual pixel is any pixel access that is outside the
2717% boundaries of the image cache.
2718%
2719% The format of the GetPixelCacheVirtualMethod() method is:
2720%
2721% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2722%
2723% A description of each parameter follows:
2724%
2725% o image: the image.
2726%
2727*/
cristyd1dd6e42011-09-04 01:46:08 +00002728MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002729{
2730 CacheInfo
2731 *cache_info;
2732
2733 assert(image != (Image *) NULL);
2734 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002735 assert(image->cache != (Cache) NULL);
2736 cache_info=(CacheInfo *) image->cache;
2737 assert(cache_info->signature == MagickSignature);
2738 return(cache_info->virtual_pixel_method);
2739}
2740
2741/*
2742%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2743% %
2744% %
2745% %
cristy4c08aed2011-07-01 19:47:50 +00002746+ 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 +00002747% %
2748% %
2749% %
2750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2751%
cristy4c08aed2011-07-01 19:47:50 +00002752% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2753% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002754%
cristy4c08aed2011-07-01 19:47:50 +00002755% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002756%
cristy4c08aed2011-07-01 19:47:50 +00002757% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002758%
2759% A description of each parameter follows:
2760%
2761% o image: the image.
2762%
2763*/
cristy4c08aed2011-07-01 19:47:50 +00002764static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002765{
2766 CacheInfo
2767 *cache_info;
2768
cristy5c9e6f22010-09-17 17:31:01 +00002769 const int
2770 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002771
cristy4c08aed2011-07-01 19:47:50 +00002772 const void
2773 *metacontent;
2774
cristye7cc7cf2010-09-21 13:26:47 +00002775 assert(image != (const Image *) NULL);
2776 assert(image->signature == MagickSignature);
2777 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002778 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002779 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002780 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002781 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2782 cache_info->nexus_info[id]);
2783 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002784}
2785
2786/*
2787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2788% %
2789% %
2790% %
cristy4c08aed2011-07-01 19:47:50 +00002791+ 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 +00002792% %
2793% %
2794% %
2795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796%
cristy4c08aed2011-07-01 19:47:50 +00002797% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2798% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002799%
cristy4c08aed2011-07-01 19:47:50 +00002800% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002801%
cristy4c08aed2011-07-01 19:47:50 +00002802% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002803% NexusInfo *nexus_info)
2804%
2805% A description of each parameter follows:
2806%
2807% o cache: the pixel cache.
2808%
cristy4c08aed2011-07-01 19:47:50 +00002809% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002810%
2811*/
cristya6577ff2011-09-02 19:54:26 +00002812MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002813 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002814{
2815 CacheInfo
2816 *cache_info;
2817
cristye7cc7cf2010-09-21 13:26:47 +00002818 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002819 cache_info=(CacheInfo *) cache;
2820 assert(cache_info->signature == MagickSignature);
2821 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002822 return((void *) NULL);
2823 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002824}
2825
2826/*
2827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2828% %
2829% %
2830% %
cristy4c08aed2011-07-01 19:47:50 +00002831% 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 +00002832% %
2833% %
2834% %
2835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2836%
cristy4c08aed2011-07-01 19:47:50 +00002837% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2838% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2839% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002840%
cristy4c08aed2011-07-01 19:47:50 +00002841% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002842%
cristy4c08aed2011-07-01 19:47:50 +00002843% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002844%
2845% A description of each parameter follows:
2846%
2847% o image: the image.
2848%
2849*/
cristy4c08aed2011-07-01 19:47:50 +00002850MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002851{
2852 CacheInfo
2853 *cache_info;
2854
cristy2036f5c2010-09-19 21:18:17 +00002855 const int
2856 id = GetOpenMPThreadId();
2857
cristy4c08aed2011-07-01 19:47:50 +00002858 const void
2859 *metacontent;
2860
cristy3ed852e2009-09-05 21:47:34 +00002861 assert(image != (const Image *) NULL);
2862 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002863 assert(image->cache != (Cache) NULL);
2864 cache_info=(CacheInfo *) image->cache;
2865 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002866 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2867 if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
2868 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002869 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002870 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2871 cache_info->nexus_info[id]);
2872 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002873}
2874
2875/*
2876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2877% %
2878% %
2879% %
2880+ G e t V i r t u a l P i x e l s F r o m N e x u s %
2881% %
2882% %
2883% %
2884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885%
2886% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2887% pixel cache as defined by the geometry parameters. A pointer to the pixels
2888% is returned if the pixels are transferred, otherwise a NULL is returned.
2889%
2890% The format of the GetVirtualPixelsFromNexus() method is:
2891%
cristy4c08aed2011-07-01 19:47:50 +00002892% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002893% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002894% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2895% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002896%
2897% A description of each parameter follows:
2898%
2899% o image: the image.
2900%
2901% o virtual_pixel_method: the virtual pixel method.
2902%
2903% o x,y,columns,rows: These values define the perimeter of a region of
2904% pixels.
2905%
2906% o nexus_info: the cache nexus to acquire.
2907%
2908% o exception: return any errors or warnings in this structure.
2909%
2910*/
2911
cristybb503372010-05-27 20:51:26 +00002912static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002913 DitherMatrix[64] =
2914 {
2915 0, 48, 12, 60, 3, 51, 15, 63,
2916 32, 16, 44, 28, 35, 19, 47, 31,
2917 8, 56, 4, 52, 11, 59, 7, 55,
2918 40, 24, 36, 20, 43, 27, 39, 23,
2919 2, 50, 14, 62, 1, 49, 13, 61,
2920 34, 18, 46, 30, 33, 17, 45, 29,
2921 10, 58, 6, 54, 9, 57, 5, 53,
2922 42, 26, 38, 22, 41, 25, 37, 21
2923 };
2924
cristybb503372010-05-27 20:51:26 +00002925static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002926{
cristybb503372010-05-27 20:51:26 +00002927 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002928 index;
2929
2930 index=x+DitherMatrix[x & 0x07]-32L;
2931 if (index < 0L)
2932 return(0L);
cristybb503372010-05-27 20:51:26 +00002933 if (index >= (ssize_t) columns)
2934 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002935 return(index);
2936}
2937
cristybb503372010-05-27 20:51:26 +00002938static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002939{
cristybb503372010-05-27 20:51:26 +00002940 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002941 index;
2942
2943 index=y+DitherMatrix[y & 0x07]-32L;
2944 if (index < 0L)
2945 return(0L);
cristybb503372010-05-27 20:51:26 +00002946 if (index >= (ssize_t) rows)
2947 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002948 return(index);
2949}
2950
cristybb503372010-05-27 20:51:26 +00002951static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002952{
2953 if (x < 0L)
2954 return(0L);
cristybb503372010-05-27 20:51:26 +00002955 if (x >= (ssize_t) columns)
2956 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002957 return(x);
2958}
2959
cristybb503372010-05-27 20:51:26 +00002960static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002961{
2962 if (y < 0L)
2963 return(0L);
cristybb503372010-05-27 20:51:26 +00002964 if (y >= (ssize_t) rows)
2965 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002966 return(y);
2967}
2968
cristybb503372010-05-27 20:51:26 +00002969static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002970{
cristybb503372010-05-27 20:51:26 +00002971 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002972}
2973
cristybb503372010-05-27 20:51:26 +00002974static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002975{
cristybb503372010-05-27 20:51:26 +00002976 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002977}
2978
cristybb503372010-05-27 20:51:26 +00002979static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2980 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002981{
2982 MagickModulo
2983 modulo;
2984
cristy6162bb42011-07-18 11:34:09 +00002985 /*
2986 Compute the remainder of dividing offset by extent. It returns not only
2987 the quotient (tile the offset falls in) but also the positive remainer
2988 within that tile such that 0 <= remainder < extent. This method is
2989 essentially a ldiv() using a floored modulo division rather than the
2990 normal default truncated modulo division.
2991 */
cristybb503372010-05-27 20:51:26 +00002992 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002993 if (offset < 0L)
2994 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00002995 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002996 return(modulo);
2997}
2998
cristya6577ff2011-09-02 19:54:26 +00002999MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003000 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3001 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003002 ExceptionInfo *exception)
3003{
3004 CacheInfo
3005 *cache_info;
3006
3007 MagickOffsetType
3008 offset;
3009
3010 MagickSizeType
3011 length,
3012 number_pixels;
3013
3014 NexusInfo
3015 **virtual_nexus;
3016
cristy4c08aed2011-07-01 19:47:50 +00003017 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003018 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003019 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003020
3021 RectangleInfo
3022 region;
3023
cristy4c08aed2011-07-01 19:47:50 +00003024 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003025 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003026
cristy4c08aed2011-07-01 19:47:50 +00003027 register const void
3028 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003029
cristy4c08aed2011-07-01 19:47:50 +00003030 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003031 *restrict q;
3032
cristybb503372010-05-27 20:51:26 +00003033 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003034 i,
3035 u;
cristy3ed852e2009-09-05 21:47:34 +00003036
cristy4c08aed2011-07-01 19:47:50 +00003037 register unsigned char
3038 *restrict s;
3039
cristy105ba3c2011-07-18 02:28:38 +00003040 ssize_t
3041 v;
3042
cristy4c08aed2011-07-01 19:47:50 +00003043 void
cristy105ba3c2011-07-18 02:28:38 +00003044 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003045
cristy3ed852e2009-09-05 21:47:34 +00003046 /*
3047 Acquire pixels.
3048 */
cristye7cc7cf2010-09-21 13:26:47 +00003049 assert(image != (const Image *) NULL);
3050 assert(image->signature == MagickSignature);
3051 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003052 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003053 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003054 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003055 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003056 region.x=x;
3057 region.y=y;
3058 region.width=columns;
3059 region.height=rows;
3060 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003061 if (pixels == (Quantum *) NULL)
3062 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003063 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003064 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3065 nexus_info->region.x;
3066 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3067 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003068 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3069 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003070 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3071 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003072 {
3073 MagickBooleanType
3074 status;
3075
3076 /*
3077 Pixel request is inside cache extents.
3078 */
cristy4c08aed2011-07-01 19:47:50 +00003079 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003080 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003081 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3082 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003083 return((const Quantum *) NULL);
3084 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003085 {
cristy4c08aed2011-07-01 19:47:50 +00003086 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003087 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003088 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003089 }
cristyacd2ed22011-08-30 01:44:23 +00003090 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003091 }
3092 /*
3093 Pixel request is outside cache extents.
3094 */
cristy4c08aed2011-07-01 19:47:50 +00003095 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003096 virtual_nexus=AcquirePixelCacheNexus(1);
3097 if (virtual_nexus == (NexusInfo **) NULL)
3098 {
cristy4c08aed2011-07-01 19:47:50 +00003099 if (virtual_nexus != (NexusInfo **) NULL)
3100 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003101 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3102 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003103 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003104 }
cristy105ba3c2011-07-18 02:28:38 +00003105 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3106 sizeof(*virtual_pixel));
3107 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003108 switch (virtual_pixel_method)
3109 {
cristy4c08aed2011-07-01 19:47:50 +00003110 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003111 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003112 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003113 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003114 case MaskVirtualPixelMethod:
3115 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003116 case EdgeVirtualPixelMethod:
3117 case CheckerTileVirtualPixelMethod:
3118 case HorizontalTileVirtualPixelMethod:
3119 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 {
cristy4c08aed2011-07-01 19:47:50 +00003121 if (cache_info->metacontent_extent != 0)
3122 {
cristy6162bb42011-07-18 11:34:09 +00003123 /*
3124 Acquire a metacontent buffer.
3125 */
cristya64b85d2011-09-14 01:02:31 +00003126 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003127 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003128 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003129 {
cristy4c08aed2011-07-01 19:47:50 +00003130 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3131 (void) ThrowMagickException(exception,GetMagickModule(),
3132 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3133 return((const Quantum *) NULL);
3134 }
cristy105ba3c2011-07-18 02:28:38 +00003135 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003136 cache_info->metacontent_extent);
3137 }
3138 switch (virtual_pixel_method)
3139 {
3140 case BlackVirtualPixelMethod:
3141 {
cristy30301712011-07-18 15:06:51 +00003142 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3143 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003144 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3145 break;
3146 }
3147 case GrayVirtualPixelMethod:
3148 {
cristy30301712011-07-18 15:06:51 +00003149 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003150 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3151 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003152 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3153 break;
3154 }
3155 case TransparentVirtualPixelMethod:
3156 {
cristy30301712011-07-18 15:06:51 +00003157 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3158 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003159 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3160 break;
3161 }
3162 case MaskVirtualPixelMethod:
3163 case WhiteVirtualPixelMethod:
3164 {
cristy30301712011-07-18 15:06:51 +00003165 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3166 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003167 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3168 break;
3169 }
3170 default:
3171 {
cristy9e0719b2011-12-29 03:45:45 +00003172 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3173 virtual_pixel);
3174 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3175 virtual_pixel);
3176 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3177 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003178 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3179 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003180 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3181 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003182 break;
3183 }
3184 }
cristy3ed852e2009-09-05 21:47:34 +00003185 break;
3186 }
3187 default:
cristy3ed852e2009-09-05 21:47:34 +00003188 break;
cristy3ed852e2009-09-05 21:47:34 +00003189 }
cristybb503372010-05-27 20:51:26 +00003190 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003191 {
cristybb503372010-05-27 20:51:26 +00003192 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003193 {
3194 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003195 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003196 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3197 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003198 {
3199 MagickModulo
3200 x_modulo,
3201 y_modulo;
3202
3203 /*
3204 Transfer a single pixel.
3205 */
3206 length=(MagickSizeType) 1;
3207 switch (virtual_pixel_method)
3208 {
cristy3ed852e2009-09-05 21:47:34 +00003209 default:
3210 {
3211 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003212 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003213 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003214 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003215 break;
3216 }
3217 case RandomVirtualPixelMethod:
3218 {
3219 if (cache_info->random_info == (RandomInfo *) NULL)
3220 cache_info->random_info=AcquireRandomInfo();
3221 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003222 RandomX(cache_info->random_info,cache_info->columns),
3223 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003224 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003225 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003226 break;
3227 }
3228 case DitherVirtualPixelMethod:
3229 {
3230 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003231 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003232 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003233 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003234 break;
3235 }
3236 case TileVirtualPixelMethod:
3237 {
3238 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3239 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3240 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003241 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003242 exception);
cristy4c08aed2011-07-01 19:47:50 +00003243 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003244 break;
3245 }
3246 case MirrorVirtualPixelMethod:
3247 {
3248 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3249 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003250 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003251 x_modulo.remainder-1L;
3252 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3253 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003254 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003255 y_modulo.remainder-1L;
3256 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003257 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003258 exception);
cristy4c08aed2011-07-01 19:47:50 +00003259 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003260 break;
3261 }
3262 case HorizontalTileEdgeVirtualPixelMethod:
3263 {
3264 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3265 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003266 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003267 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003268 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003269 break;
3270 }
3271 case VerticalTileEdgeVirtualPixelMethod:
3272 {
3273 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3274 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003275 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003276 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003277 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3278 break;
3279 }
3280 case BackgroundVirtualPixelMethod:
3281 case BlackVirtualPixelMethod:
3282 case GrayVirtualPixelMethod:
3283 case TransparentVirtualPixelMethod:
3284 case MaskVirtualPixelMethod:
3285 case WhiteVirtualPixelMethod:
3286 {
3287 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003288 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003289 break;
3290 }
3291 case EdgeVirtualPixelMethod:
3292 case CheckerTileVirtualPixelMethod:
3293 {
3294 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3295 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3296 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3297 {
3298 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003299 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003300 break;
3301 }
3302 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3303 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3304 exception);
3305 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3306 break;
3307 }
3308 case HorizontalTileVirtualPixelMethod:
3309 {
3310 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3311 {
3312 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003313 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003314 break;
3315 }
3316 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3317 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3318 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3319 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3320 exception);
3321 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3322 break;
3323 }
3324 case VerticalTileVirtualPixelMethod:
3325 {
3326 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3327 {
3328 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003329 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003330 break;
3331 }
3332 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3333 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3335 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3336 exception);
3337 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003338 break;
3339 }
3340 }
cristy4c08aed2011-07-01 19:47:50 +00003341 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003342 break;
cristyed231572011-07-14 02:18:59 +00003343 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003344 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003345 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003346 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003347 {
3348 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3349 s+=cache_info->metacontent_extent;
3350 }
cristy3ed852e2009-09-05 21:47:34 +00003351 continue;
3352 }
3353 /*
3354 Transfer a run of pixels.
3355 */
cristy4c08aed2011-07-01 19:47:50 +00003356 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3357 length,1UL,*virtual_nexus,exception);
3358 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003359 break;
cristy4c08aed2011-07-01 19:47:50 +00003360 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003361 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3362 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003363 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003364 {
cristy4c08aed2011-07-01 19:47:50 +00003365 (void) memcpy(s,r,(size_t) length);
3366 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003367 }
3368 }
3369 }
cristy4c08aed2011-07-01 19:47:50 +00003370 /*
3371 Free resources.
3372 */
cristy105ba3c2011-07-18 02:28:38 +00003373 if (virtual_metacontent != (void *) NULL)
3374 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003375 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3376 return(pixels);
3377}
3378
3379/*
3380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3381% %
3382% %
3383% %
3384+ G e t V i r t u a l P i x e l C a c h e %
3385% %
3386% %
3387% %
3388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3389%
3390% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3391% cache as defined by the geometry parameters. A pointer to the pixels
3392% is returned if the pixels are transferred, otherwise a NULL is returned.
3393%
3394% The format of the GetVirtualPixelCache() method is:
3395%
cristy4c08aed2011-07-01 19:47:50 +00003396% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003397% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3398% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003399% ExceptionInfo *exception)
3400%
3401% A description of each parameter follows:
3402%
3403% o image: the image.
3404%
3405% o virtual_pixel_method: the virtual pixel method.
3406%
3407% o x,y,columns,rows: These values define the perimeter of a region of
3408% pixels.
3409%
3410% o exception: return any errors or warnings in this structure.
3411%
3412*/
cristy4c08aed2011-07-01 19:47:50 +00003413static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003414 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3415 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003416{
3417 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003418 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003419
cristy5c9e6f22010-09-17 17:31:01 +00003420 const int
3421 id = GetOpenMPThreadId();
3422
cristy4c08aed2011-07-01 19:47:50 +00003423 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003424 *p;
cristy4c08aed2011-07-01 19:47:50 +00003425
cristye7cc7cf2010-09-21 13:26:47 +00003426 assert(image != (const Image *) NULL);
3427 assert(image->signature == MagickSignature);
3428 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003429 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003430 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003431 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003432 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003433 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003434 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003435}
3436
3437/*
3438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3439% %
3440% %
3441% %
3442% G e t V i r t u a l P i x e l Q u e u e %
3443% %
3444% %
3445% %
3446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3447%
cristy4c08aed2011-07-01 19:47:50 +00003448% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3449% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003450%
3451% The format of the GetVirtualPixelQueue() method is:
3452%
cristy4c08aed2011-07-01 19:47:50 +00003453% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003454%
3455% A description of each parameter follows:
3456%
3457% o image: the image.
3458%
3459*/
cristy4c08aed2011-07-01 19:47:50 +00003460MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003461{
3462 CacheInfo
3463 *cache_info;
3464
cristy2036f5c2010-09-19 21:18:17 +00003465 const int
3466 id = GetOpenMPThreadId();
3467
cristy3ed852e2009-09-05 21:47:34 +00003468 assert(image != (const Image *) NULL);
3469 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003470 assert(image->cache != (Cache) NULL);
3471 cache_info=(CacheInfo *) image->cache;
3472 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003473 if (cache_info->methods.get_virtual_pixels_handler !=
3474 (GetVirtualPixelsHandler) NULL)
3475 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003476 assert(id < (int) cache_info->number_threads);
3477 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003478}
3479
3480/*
3481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3482% %
3483% %
3484% %
3485% G e t V i r t u a l P i x e l s %
3486% %
3487% %
3488% %
3489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3490%
3491% GetVirtualPixels() returns an immutable pixel region. If the
3492% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003493% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003494% copy of the pixels or it may point to the original pixels in memory.
3495% Performance is maximized if the selected region is part of one row, or one
3496% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003497% (without a copy) if the image is in memory, or in a memory-mapped file. The
3498% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003499%
3500% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003501% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3502% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3503% access the meta-content (of type void) corresponding to the the
3504% region.
cristy3ed852e2009-09-05 21:47:34 +00003505%
3506% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3507%
3508% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3509% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3510% GetCacheViewAuthenticPixels() instead.
3511%
3512% The format of the GetVirtualPixels() method is:
3513%
cristy4c08aed2011-07-01 19:47:50 +00003514% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003515% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003516% ExceptionInfo *exception)
3517%
3518% A description of each parameter follows:
3519%
3520% o image: the image.
3521%
3522% o x,y,columns,rows: These values define the perimeter of a region of
3523% pixels.
3524%
3525% o exception: return any errors or warnings in this structure.
3526%
3527*/
cristy4c08aed2011-07-01 19:47:50 +00003528MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003529 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3530 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003531{
3532 CacheInfo
3533 *cache_info;
3534
cristy2036f5c2010-09-19 21:18:17 +00003535 const int
3536 id = GetOpenMPThreadId();
3537
cristy4c08aed2011-07-01 19:47:50 +00003538 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003539 *p;
cristy4c08aed2011-07-01 19:47:50 +00003540
cristy3ed852e2009-09-05 21:47:34 +00003541 assert(image != (const Image *) NULL);
3542 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003543 assert(image->cache != (Cache) NULL);
3544 cache_info=(CacheInfo *) image->cache;
3545 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003546 if (cache_info->methods.get_virtual_pixel_handler !=
3547 (GetVirtualPixelHandler) NULL)
3548 return(cache_info->methods.get_virtual_pixel_handler(image,
3549 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003550 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003551 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003552 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003553 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003554}
3555
3556/*
3557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3558% %
3559% %
3560% %
3561+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3562% %
3563% %
3564% %
3565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3566%
cristy4c08aed2011-07-01 19:47:50 +00003567% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3568% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003569%
3570% The format of the GetVirtualPixelsCache() method is:
3571%
cristy4c08aed2011-07-01 19:47:50 +00003572% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003573%
3574% A description of each parameter follows:
3575%
3576% o image: the image.
3577%
3578*/
cristy4c08aed2011-07-01 19:47:50 +00003579static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003580{
3581 CacheInfo
3582 *cache_info;
3583
cristy5c9e6f22010-09-17 17:31:01 +00003584 const int
3585 id = GetOpenMPThreadId();
3586
cristye7cc7cf2010-09-21 13:26:47 +00003587 assert(image != (const Image *) NULL);
3588 assert(image->signature == MagickSignature);
3589 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003590 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003591 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003592 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003593 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003594}
3595
3596/*
3597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3598% %
3599% %
3600% %
3601+ G e t V i r t u a l P i x e l s N e x u s %
3602% %
3603% %
3604% %
3605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3606%
3607% GetVirtualPixelsNexus() returns the pixels associated with the specified
3608% cache nexus.
3609%
3610% The format of the GetVirtualPixelsNexus() method is:
3611%
cristy4c08aed2011-07-01 19:47:50 +00003612% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003613% NexusInfo *nexus_info)
3614%
3615% A description of each parameter follows:
3616%
3617% o cache: the pixel cache.
3618%
3619% o nexus_info: the cache nexus to return the colormap pixels.
3620%
3621*/
cristya6577ff2011-09-02 19:54:26 +00003622MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003623 NexusInfo *nexus_info)
3624{
3625 CacheInfo
3626 *cache_info;
3627
cristye7cc7cf2010-09-21 13:26:47 +00003628 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003629 cache_info=(CacheInfo *) cache;
3630 assert(cache_info->signature == MagickSignature);
3631 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003632 return((Quantum *) NULL);
3633 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003634}
3635
3636/*
3637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3638% %
3639% %
3640% %
cristy3ed852e2009-09-05 21:47:34 +00003641+ O p e n P i x e l C a c h e %
3642% %
3643% %
3644% %
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646%
3647% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3648% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003649% metacontent, and memory mapping the cache if it is disk based. The cache
3650% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003651%
3652% The format of the OpenPixelCache() method is:
3653%
3654% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3655% ExceptionInfo *exception)
3656%
3657% A description of each parameter follows:
3658%
3659% o image: the image.
3660%
3661% o mode: ReadMode, WriteMode, or IOMode.
3662%
3663% o exception: return any errors or warnings in this structure.
3664%
3665*/
3666
cristyd43a46b2010-01-21 02:13:41 +00003667static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003668{
3669 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003670 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003671 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003672 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003673 {
3674 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003675 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003676 cache_info->length);
3677 }
3678}
3679
3680static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3681{
3682 CacheInfo
3683 *cache_info;
3684
3685 MagickOffsetType
3686 count,
3687 extent,
3688 offset;
3689
3690 cache_info=(CacheInfo *) image->cache;
3691 if (image->debug != MagickFalse)
3692 {
3693 char
3694 format[MaxTextExtent],
3695 message[MaxTextExtent];
3696
cristyb9080c92009-12-01 20:13:26 +00003697 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003698 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003699 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003700 cache_info->cache_filename,cache_info->file,format);
3701 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3702 }
3703 if (length != (MagickSizeType) ((MagickOffsetType) length))
3704 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003705 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003706 if (extent < 0)
3707 return(MagickFalse);
3708 if ((MagickSizeType) extent >= length)
3709 return(MagickTrue);
3710 offset=(MagickOffsetType) length-1;
3711 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3712 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3713}
3714
3715static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3716 ExceptionInfo *exception)
3717{
cristy3ed852e2009-09-05 21:47:34 +00003718 CacheInfo
3719 *cache_info,
3720 source_info;
3721
cristyf3a6a9d2010-11-07 21:02:56 +00003722 char
3723 format[MaxTextExtent],
3724 message[MaxTextExtent];
3725
cristy4c08aed2011-07-01 19:47:50 +00003726 MagickBooleanType
3727 status;
3728
cristy3ed852e2009-09-05 21:47:34 +00003729 MagickSizeType
3730 length,
3731 number_pixels;
3732
cristy3b8fe922011-12-29 18:56:23 +00003733 PixelChannelMap
3734 *p,
3735 *q;
3736
cristy3ed852e2009-09-05 21:47:34 +00003737 size_t
cristye076a6e2010-08-15 19:59:43 +00003738 columns,
cristy3ed852e2009-09-05 21:47:34 +00003739 packet_size;
3740
cristye7cc7cf2010-09-21 13:26:47 +00003741 assert(image != (const Image *) NULL);
3742 assert(image->signature == MagickSignature);
3743 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003744 if (image->debug != MagickFalse)
3745 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3746 if ((image->columns == 0) || (image->rows == 0))
3747 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3748 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003749 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003750 source_info=(*cache_info);
3751 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003752 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003753 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003754 cache_info->storage_class=image->storage_class;
3755 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003756 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003757 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003758 cache_info->rows=image->rows;
3759 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003760 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003761 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003762 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3763 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003764 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003765 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003766 if (image->ping != MagickFalse)
3767 {
cristy73724512010-04-12 14:43:14 +00003768 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003769 cache_info->pixels=(Quantum *) NULL;
3770 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003771 cache_info->length=0;
3772 return(MagickTrue);
3773 }
cristy3ed852e2009-09-05 21:47:34 +00003774 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003775 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003776 if (image->metacontent_extent != 0)
3777 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003778 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003779 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003780 if (cache_info->columns != columns)
3781 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3782 image->filename);
3783 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00003784 p=cache_info->channel_map;
3785 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00003786 if ((cache_info->type != UndefinedCache) &&
3787 (cache_info->columns <= source_info.columns) &&
3788 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00003789 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00003790 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00003791 (cache_info->metacontent_extent <= source_info.metacontent_extent))
3792 {
3793 /*
3794 Inline pixel cache clone optimization.
3795 */
3796 if ((cache_info->columns == source_info.columns) &&
3797 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00003798 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00003799 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00003800 (cache_info->metacontent_extent == source_info.metacontent_extent))
3801 return(MagickTrue);
3802 return(ClonePixelCachePixels(cache_info,&source_info,exception));
3803 }
cristy3ed852e2009-09-05 21:47:34 +00003804 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003805 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003806 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003807 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3808 {
3809 status=AcquireMagickResource(MemoryResource,cache_info->length);
3810 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3811 (cache_info->type == MemoryCache))
3812 {
cristyd43a46b2010-01-21 02:13:41 +00003813 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003814 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003815 cache_info->pixels=source_info.pixels;
3816 else
3817 {
3818 /*
3819 Create memory pixel cache.
3820 */
cristy4c08aed2011-07-01 19:47:50 +00003821 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003822 if (image->debug != MagickFalse)
3823 {
cristy32cacff2011-12-31 03:36:27 +00003824 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003825 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003826 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3827 cache_info->filename,cache_info->mapped != MagickFalse ?
3828 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003829 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003830 format);
cristy3ed852e2009-09-05 21:47:34 +00003831 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3832 message);
3833 }
cristy3ed852e2009-09-05 21:47:34 +00003834 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003835 cache_info->metacontent=(void *) NULL;
3836 if (cache_info->metacontent_extent != 0)
3837 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003838 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003839 if ((source_info.storage_class != UndefinedClass) &&
3840 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003841 {
cristy4c08aed2011-07-01 19:47:50 +00003842 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003843 exception);
3844 RelinquishPixelCachePixels(&source_info);
3845 }
cristy4c08aed2011-07-01 19:47:50 +00003846 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003847 }
3848 }
3849 RelinquishMagickResource(MemoryResource,cache_info->length);
3850 }
3851 /*
3852 Create pixel cache on disk.
3853 */
3854 status=AcquireMagickResource(DiskResource,cache_info->length);
3855 if (status == MagickFalse)
3856 {
3857 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3858 "CacheResourcesExhausted","`%s'",image->filename);
3859 return(MagickFalse);
3860 }
cristy413f1302012-01-01 17:48:27 +00003861 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3862 {
3863 (void) ClosePixelCacheOnDisk(cache_info);
3864 *cache_info->cache_filename='\0';
3865 }
cristy3ed852e2009-09-05 21:47:34 +00003866 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3867 {
3868 RelinquishMagickResource(DiskResource,cache_info->length);
3869 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3870 image->filename);
3871 return(MagickFalse);
3872 }
3873 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3874 cache_info->length);
3875 if (status == MagickFalse)
3876 {
3877 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3878 image->filename);
3879 return(MagickFalse);
3880 }
cristyed231572011-07-14 02:18:59 +00003881 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003882 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003883 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003884 cache_info->type=DiskCache;
3885 else
3886 {
3887 status=AcquireMagickResource(MapResource,cache_info->length);
3888 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3889 (cache_info->type != MemoryCache))
3890 cache_info->type=DiskCache;
3891 else
3892 {
cristy4c08aed2011-07-01 19:47:50 +00003893 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003894 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003895 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003896 {
cristy3ed852e2009-09-05 21:47:34 +00003897 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003898 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003899 }
3900 else
3901 {
3902 /*
3903 Create file-backed memory-mapped pixel cache.
3904 */
cristy4c08aed2011-07-01 19:47:50 +00003905 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003906 (void) ClosePixelCacheOnDisk(cache_info);
3907 cache_info->type=MapCache;
3908 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003909 cache_info->metacontent=(void *) NULL;
3910 if (cache_info->metacontent_extent != 0)
3911 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003912 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003913 if ((source_info.storage_class != UndefinedClass) &&
3914 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003915 {
3916 status=ClonePixelCachePixels(cache_info,&source_info,
3917 exception);
3918 RelinquishPixelCachePixels(&source_info);
3919 }
3920 if (image->debug != MagickFalse)
3921 {
cristy413f1302012-01-01 17:48:27 +00003922 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003923 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003924 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003925 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003926 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003927 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003928 format);
cristy3ed852e2009-09-05 21:47:34 +00003929 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3930 message);
3931 }
cristy4c08aed2011-07-01 19:47:50 +00003932 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003933 }
3934 }
3935 RelinquishMagickResource(MapResource,cache_info->length);
3936 }
cristy4c08aed2011-07-01 19:47:50 +00003937 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003938 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003939 {
3940 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3941 RelinquishPixelCachePixels(&source_info);
3942 }
3943 if (image->debug != MagickFalse)
3944 {
cristyb9080c92009-12-01 20:13:26 +00003945 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003946 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003947 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003948 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003949 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003950 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3952 }
cristy4c08aed2011-07-01 19:47:50 +00003953 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003954}
3955
3956/*
3957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3958% %
3959% %
3960% %
3961+ P e r s i s t P i x e l C a c h e %
3962% %
3963% %
3964% %
3965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3966%
3967% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3968% persistent pixel cache is one that resides on disk and is not destroyed
3969% when the program exits.
3970%
3971% The format of the PersistPixelCache() method is:
3972%
3973% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3974% const MagickBooleanType attach,MagickOffsetType *offset,
3975% ExceptionInfo *exception)
3976%
3977% A description of each parameter follows:
3978%
3979% o image: the image.
3980%
3981% o filename: the persistent pixel cache filename.
3982%
cristyf3a6a9d2010-11-07 21:02:56 +00003983% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003984%
cristy3ed852e2009-09-05 21:47:34 +00003985% o initialize: A value other than zero initializes the persistent pixel
3986% cache.
3987%
3988% o offset: the offset in the persistent cache to store pixels.
3989%
3990% o exception: return any errors or warnings in this structure.
3991%
3992*/
3993MagickExport MagickBooleanType PersistPixelCache(Image *image,
3994 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3995 ExceptionInfo *exception)
3996{
3997 CacheInfo
3998 *cache_info,
3999 *clone_info;
4000
4001 Image
4002 clone_image;
4003
cristy3ed852e2009-09-05 21:47:34 +00004004 MagickBooleanType
4005 status;
4006
cristye076a6e2010-08-15 19:59:43 +00004007 ssize_t
4008 page_size;
4009
cristy3ed852e2009-09-05 21:47:34 +00004010 assert(image != (Image *) NULL);
4011 assert(image->signature == MagickSignature);
4012 if (image->debug != MagickFalse)
4013 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4014 assert(image->cache != (void *) NULL);
4015 assert(filename != (const char *) NULL);
4016 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004017 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004018 cache_info=(CacheInfo *) image->cache;
4019 assert(cache_info->signature == MagickSignature);
4020 if (attach != MagickFalse)
4021 {
4022 /*
cristy01b7eb02009-09-10 23:10:14 +00004023 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004024 */
4025 if (image->debug != MagickFalse)
4026 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004027 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004028 (void) CopyMagickString(cache_info->cache_filename,filename,
4029 MaxTextExtent);
4030 cache_info->type=DiskCache;
4031 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004032 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004033 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004034 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004035 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004036 }
cristy01b7eb02009-09-10 23:10:14 +00004037 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4038 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004039 {
cristyf84a1932010-01-03 18:00:18 +00004040 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004041 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004042 (cache_info->reference_count == 1))
4043 {
4044 int
4045 status;
4046
4047 /*
cristy01b7eb02009-09-10 23:10:14 +00004048 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004049 */
cristy320684d2011-09-23 14:55:47 +00004050 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004051 if (status == 0)
4052 {
4053 (void) CopyMagickString(cache_info->cache_filename,filename,
4054 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004055 *offset+=cache_info->length+page_size-(cache_info->length %
4056 page_size);
cristyf84a1932010-01-03 18:00:18 +00004057 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004058 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004059 if (image->debug != MagickFalse)
4060 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4061 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004062 return(MagickTrue);
4063 }
4064 }
cristyf84a1932010-01-03 18:00:18 +00004065 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004066 }
4067 /*
cristy01b7eb02009-09-10 23:10:14 +00004068 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004069 */
4070 clone_image=(*image);
4071 clone_info=(CacheInfo *) clone_image.cache;
4072 image->cache=ClonePixelCache(cache_info);
4073 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4074 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4075 cache_info->type=DiskCache;
4076 cache_info->offset=(*offset);
4077 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004078 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004079 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004080 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004081 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004082 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4083 return(status);
4084}
4085
4086/*
4087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4088% %
4089% %
4090% %
cristyc11dace2012-01-24 16:39:46 +00004091+ Q u e u e A u t h e n t i c P i x e l C a c h e N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00004092% %
4093% %
4094% %
4095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4096%
cristyc11dace2012-01-24 16:39:46 +00004097% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4098% defined by the region rectangle and returns a pointer to the region. This
4099% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004100% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4101% pixels are transferred, otherwise a NULL is returned.
4102%
cristyc11dace2012-01-24 16:39:46 +00004103% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004104%
cristyc11dace2012-01-24 16:39:46 +00004105% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004106% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004107% const MagickBooleanType clone,NexusInfo *nexus_info,
4108% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004109%
4110% A description of each parameter follows:
4111%
4112% o image: the image.
4113%
4114% o x,y,columns,rows: These values define the perimeter of a region of
4115% pixels.
4116%
4117% o nexus_info: the cache nexus to set.
4118%
cristy65dbf172011-10-06 17:32:04 +00004119% o clone: clone the pixel cache.
4120%
cristy3ed852e2009-09-05 21:47:34 +00004121% o exception: return any errors or warnings in this structure.
4122%
4123*/
cristyc11dace2012-01-24 16:39:46 +00004124MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4125 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004126 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004127{
4128 CacheInfo
4129 *cache_info;
4130
4131 MagickOffsetType
4132 offset;
4133
4134 MagickSizeType
4135 number_pixels;
4136
4137 RectangleInfo
4138 region;
4139
4140 /*
4141 Validate pixel cache geometry.
4142 */
cristye7cc7cf2010-09-21 13:26:47 +00004143 assert(image != (const Image *) NULL);
4144 assert(image->signature == MagickSignature);
4145 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004146 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004147 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004148 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004149 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004150 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4151 {
4152 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4153 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004154 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004155 }
cristybb503372010-05-27 20:51:26 +00004156 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4157 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004158 {
4159 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4160 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004161 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004162 }
4163 offset=(MagickOffsetType) y*cache_info->columns+x;
4164 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004165 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004166 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4167 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4168 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004169 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004170 /*
4171 Return pixel cache.
4172 */
4173 region.x=x;
4174 region.y=y;
4175 region.width=columns;
4176 region.height=rows;
4177 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4178}
4179
4180/*
4181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4182% %
4183% %
4184% %
4185+ Q u e u e A u t h e n t i c P i x e l s C a c h e %
4186% %
4187% %
4188% %
4189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4190%
4191% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4192% defined by the region rectangle and returns a pointer to the region. This
4193% region is subsequently transferred from the pixel cache with
4194% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4195% pixels are transferred, otherwise a NULL is returned.
4196%
4197% The format of the QueueAuthenticPixelsCache() method is:
4198%
cristy4c08aed2011-07-01 19:47:50 +00004199% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004200% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004201% ExceptionInfo *exception)
4202%
4203% A description of each parameter follows:
4204%
4205% o image: the image.
4206%
4207% o x,y,columns,rows: These values define the perimeter of a region of
4208% pixels.
4209%
4210% o exception: return any errors or warnings in this structure.
4211%
4212*/
cristy4c08aed2011-07-01 19:47:50 +00004213static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004214 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004215 ExceptionInfo *exception)
4216{
4217 CacheInfo
4218 *cache_info;
4219
cristy5c9e6f22010-09-17 17:31:01 +00004220 const int
4221 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004222
cristy4c08aed2011-07-01 19:47:50 +00004223 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004224 *q;
cristy4c08aed2011-07-01 19:47:50 +00004225
cristye7cc7cf2010-09-21 13:26:47 +00004226 assert(image != (const Image *) NULL);
4227 assert(image->signature == MagickSignature);
4228 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004229 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004230 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004231 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004232 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004233 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004234 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004235}
4236
4237/*
4238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4239% %
4240% %
4241% %
4242% Q u e u e A u t h e n t i c P i x e l s %
4243% %
4244% %
4245% %
4246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4247%
4248% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004249% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004250% region is returned, otherwise NULL is returned. The returned pointer may
4251% point to a temporary working buffer for the pixels or it may point to the
4252% final location of the pixels in memory.
4253%
4254% Write-only access means that any existing pixel values corresponding to
4255% the region are ignored. This is useful if the initial image is being
4256% created from scratch, or if the existing pixel values are to be
4257% completely replaced without need to refer to their pre-existing values.
4258% The application is free to read and write the pixel buffer returned by
4259% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4260% initialize the pixel array values. Initializing pixel array values is the
4261% application's responsibility.
4262%
4263% Performance is maximized if the selected region is part of one row, or
4264% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004265% pixels in-place (without a copy) if the image is in memory, or in a
4266% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004267% by the user.
4268%
4269% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004270% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4271% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4272% obtain the meta-content (of type void) corresponding to the region.
4273% Once the Quantum (and/or Quantum) array has been updated, the
4274% changes must be saved back to the underlying image using
4275% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004276%
4277% The format of the QueueAuthenticPixels() method is:
4278%
cristy4c08aed2011-07-01 19:47:50 +00004279% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004280% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004281% ExceptionInfo *exception)
4282%
4283% A description of each parameter follows:
4284%
4285% o image: the image.
4286%
4287% o x,y,columns,rows: These values define the perimeter of a region of
4288% pixels.
4289%
4290% o exception: return any errors or warnings in this structure.
4291%
4292*/
cristy4c08aed2011-07-01 19:47:50 +00004293MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004294 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004295 ExceptionInfo *exception)
4296{
4297 CacheInfo
4298 *cache_info;
4299
cristy2036f5c2010-09-19 21:18:17 +00004300 const int
4301 id = GetOpenMPThreadId();
4302
cristy4c08aed2011-07-01 19:47:50 +00004303 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004304 *q;
cristy4c08aed2011-07-01 19:47:50 +00004305
cristy3ed852e2009-09-05 21:47:34 +00004306 assert(image != (Image *) NULL);
4307 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004308 assert(image->cache != (Cache) NULL);
4309 cache_info=(CacheInfo *) image->cache;
4310 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004311 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004312 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004313 {
cristyc36c8822012-02-14 14:02:36 +00004314 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4315 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004316 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004317 }
cristy2036f5c2010-09-19 21:18:17 +00004318 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004319 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004320 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004321 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004322}
4323
4324/*
4325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4326% %
4327% %
4328% %
cristy4c08aed2011-07-01 19:47:50 +00004329+ R e a d P i x e l C a c h e M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00004330% %
4331% %
4332% %
4333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4334%
cristy4c08aed2011-07-01 19:47:50 +00004335% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004336% the pixel cache.
4337%
cristy4c08aed2011-07-01 19:47:50 +00004338% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004339%
cristy4c08aed2011-07-01 19:47:50 +00004340% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004341% NexusInfo *nexus_info,ExceptionInfo *exception)
4342%
4343% A description of each parameter follows:
4344%
4345% o cache_info: the pixel cache.
4346%
cristy4c08aed2011-07-01 19:47:50 +00004347% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004348%
4349% o exception: return any errors or warnings in this structure.
4350%
4351*/
cristy4c08aed2011-07-01 19:47:50 +00004352static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004353 NexusInfo *nexus_info,ExceptionInfo *exception)
4354{
4355 MagickOffsetType
4356 count,
4357 offset;
4358
4359 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004360 extent,
4361 length;
cristy3ed852e2009-09-05 21:47:34 +00004362
cristybb503372010-05-27 20:51:26 +00004363 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004364 y;
4365
cristy4c08aed2011-07-01 19:47:50 +00004366 register unsigned char
4367 *restrict q;
4368
cristybb503372010-05-27 20:51:26 +00004369 size_t
cristy3ed852e2009-09-05 21:47:34 +00004370 rows;
4371
cristy4c08aed2011-07-01 19:47:50 +00004372 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004373 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004374 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004375 return(MagickTrue);
4376 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4377 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004378 length=(MagickSizeType) nexus_info->region.width*
4379 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004380 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004381 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004382 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004383 switch (cache_info->type)
4384 {
4385 case MemoryCache:
4386 case MapCache:
4387 {
cristy4c08aed2011-07-01 19:47:50 +00004388 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004389 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004390
4391 /*
cristy4c08aed2011-07-01 19:47:50 +00004392 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004393 */
cristydd341db2010-03-04 19:06:38 +00004394 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004395 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004396 {
cristy48078b12010-09-23 17:11:01 +00004397 length=extent;
cristydd341db2010-03-04 19:06:38 +00004398 rows=1UL;
4399 }
cristy4c08aed2011-07-01 19:47:50 +00004400 p=(unsigned char *) cache_info->metacontent+offset*
4401 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004402 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004403 {
cristy8f036fe2010-09-18 02:02:00 +00004404 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004405 p+=cache_info->metacontent_extent*cache_info->columns;
4406 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004407 }
4408 break;
4409 }
4410 case DiskCache:
4411 {
4412 /*
cristy4c08aed2011-07-01 19:47:50 +00004413 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004414 */
4415 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4416 {
4417 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4418 cache_info->cache_filename);
4419 return(MagickFalse);
4420 }
cristydd341db2010-03-04 19:06:38 +00004421 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004422 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004423 {
cristy48078b12010-09-23 17:11:01 +00004424 length=extent;
cristydd341db2010-03-04 19:06:38 +00004425 rows=1UL;
4426 }
cristy48078b12010-09-23 17:11:01 +00004427 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004428 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004429 {
cristy48078b12010-09-23 17:11:01 +00004430 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004431 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004432 cache_info->metacontent_extent,length,(unsigned char *) q);
4433 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004434 break;
4435 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004436 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004437 }
cristyc11dace2012-01-24 16:39:46 +00004438 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4439 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004440 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004441 {
4442 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4443 cache_info->cache_filename);
4444 return(MagickFalse);
4445 }
4446 break;
4447 }
4448 default:
4449 break;
4450 }
4451 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004452 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004453 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004454 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004455 nexus_info->region.width,(double) nexus_info->region.height,(double)
4456 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004457 return(MagickTrue);
4458}
4459
4460/*
4461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4462% %
4463% %
4464% %
4465+ R e a d P i x e l C a c h e P i x e l s %
4466% %
4467% %
4468% %
4469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4470%
4471% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4472% cache.
4473%
4474% The format of the ReadPixelCachePixels() method is:
4475%
4476% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4477% NexusInfo *nexus_info,ExceptionInfo *exception)
4478%
4479% A description of each parameter follows:
4480%
4481% o cache_info: the pixel cache.
4482%
4483% o nexus_info: the cache nexus to read the pixels.
4484%
4485% o exception: return any errors or warnings in this structure.
4486%
4487*/
4488static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4489 NexusInfo *nexus_info,ExceptionInfo *exception)
4490{
4491 MagickOffsetType
4492 count,
4493 offset;
4494
4495 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004496 extent,
4497 length;
cristy3ed852e2009-09-05 21:47:34 +00004498
cristy4c08aed2011-07-01 19:47:50 +00004499 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004500 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004501
cristye076a6e2010-08-15 19:59:43 +00004502 register ssize_t
4503 y;
4504
cristybb503372010-05-27 20:51:26 +00004505 size_t
cristy3ed852e2009-09-05 21:47:34 +00004506 rows;
4507
cristy4c08aed2011-07-01 19:47:50 +00004508 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004509 return(MagickTrue);
4510 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4511 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004512 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004513 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004514 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004515 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004516 q=nexus_info->pixels;
4517 switch (cache_info->type)
4518 {
4519 case MemoryCache:
4520 case MapCache:
4521 {
cristy4c08aed2011-07-01 19:47:50 +00004522 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004523 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004524
4525 /*
4526 Read pixels from memory.
4527 */
cristydd341db2010-03-04 19:06:38 +00004528 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004529 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004530 {
cristy48078b12010-09-23 17:11:01 +00004531 length=extent;
cristydd341db2010-03-04 19:06:38 +00004532 rows=1UL;
4533 }
cristyed231572011-07-14 02:18:59 +00004534 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004535 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004536 {
cristy8f036fe2010-09-18 02:02:00 +00004537 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004538 p+=cache_info->number_channels*cache_info->columns;
4539 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004540 }
4541 break;
4542 }
4543 case DiskCache:
4544 {
4545 /*
4546 Read pixels from disk.
4547 */
4548 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4549 {
4550 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4551 cache_info->cache_filename);
4552 return(MagickFalse);
4553 }
cristydd341db2010-03-04 19:06:38 +00004554 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004555 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004556 {
cristy48078b12010-09-23 17:11:01 +00004557 length=extent;
cristydd341db2010-03-04 19:06:38 +00004558 rows=1UL;
4559 }
cristybb503372010-05-27 20:51:26 +00004560 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004561 {
4562 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004563 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004564 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004565 break;
4566 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004567 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004568 }
cristyc11dace2012-01-24 16:39:46 +00004569 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4570 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004571 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004572 {
4573 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4574 cache_info->cache_filename);
4575 return(MagickFalse);
4576 }
4577 break;
4578 }
4579 default:
4580 break;
4581 }
4582 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004583 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004584 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004585 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004586 nexus_info->region.width,(double) nexus_info->region.height,(double)
4587 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004588 return(MagickTrue);
4589}
4590
4591/*
4592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4593% %
4594% %
4595% %
4596+ R e f e r e n c e P i x e l C a c h e %
4597% %
4598% %
4599% %
4600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4601%
4602% ReferencePixelCache() increments the reference count associated with the
4603% pixel cache returning a pointer to the cache.
4604%
4605% The format of the ReferencePixelCache method is:
4606%
4607% Cache ReferencePixelCache(Cache cache_info)
4608%
4609% A description of each parameter follows:
4610%
4611% o cache_info: the pixel cache.
4612%
4613*/
cristya6577ff2011-09-02 19:54:26 +00004614MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004615{
4616 CacheInfo
4617 *cache_info;
4618
4619 assert(cache != (Cache *) NULL);
4620 cache_info=(CacheInfo *) cache;
4621 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004622 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004623 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004624 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004625 return(cache_info);
4626}
4627
4628/*
4629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4630% %
4631% %
4632% %
4633+ S e t P i x e l C a c h e M e t h o d s %
4634% %
4635% %
4636% %
4637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4638%
4639% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4640%
4641% The format of the SetPixelCacheMethods() method is:
4642%
4643% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4644%
4645% A description of each parameter follows:
4646%
4647% o cache: the pixel cache.
4648%
4649% o cache_methods: Specifies a pointer to a CacheMethods structure.
4650%
4651*/
cristya6577ff2011-09-02 19:54:26 +00004652MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004653{
4654 CacheInfo
4655 *cache_info;
4656
4657 GetOneAuthenticPixelFromHandler
4658 get_one_authentic_pixel_from_handler;
4659
4660 GetOneVirtualPixelFromHandler
4661 get_one_virtual_pixel_from_handler;
4662
4663 /*
4664 Set cache pixel methods.
4665 */
4666 assert(cache != (Cache) NULL);
4667 assert(cache_methods != (CacheMethods *) NULL);
4668 cache_info=(CacheInfo *) cache;
4669 assert(cache_info->signature == MagickSignature);
4670 if (cache_info->debug != MagickFalse)
4671 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4672 cache_info->filename);
4673 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4674 cache_info->methods.get_virtual_pixel_handler=
4675 cache_methods->get_virtual_pixel_handler;
4676 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4677 cache_info->methods.destroy_pixel_handler=
4678 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004679 if (cache_methods->get_virtual_metacontent_from_handler !=
4680 (GetVirtualMetacontentFromHandler) NULL)
4681 cache_info->methods.get_virtual_metacontent_from_handler=
4682 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004683 if (cache_methods->get_authentic_pixels_handler !=
4684 (GetAuthenticPixelsHandler) NULL)
4685 cache_info->methods.get_authentic_pixels_handler=
4686 cache_methods->get_authentic_pixels_handler;
4687 if (cache_methods->queue_authentic_pixels_handler !=
4688 (QueueAuthenticPixelsHandler) NULL)
4689 cache_info->methods.queue_authentic_pixels_handler=
4690 cache_methods->queue_authentic_pixels_handler;
4691 if (cache_methods->sync_authentic_pixels_handler !=
4692 (SyncAuthenticPixelsHandler) NULL)
4693 cache_info->methods.sync_authentic_pixels_handler=
4694 cache_methods->sync_authentic_pixels_handler;
4695 if (cache_methods->get_authentic_pixels_from_handler !=
4696 (GetAuthenticPixelsFromHandler) NULL)
4697 cache_info->methods.get_authentic_pixels_from_handler=
4698 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004699 if (cache_methods->get_authentic_metacontent_from_handler !=
4700 (GetAuthenticMetacontentFromHandler) NULL)
4701 cache_info->methods.get_authentic_metacontent_from_handler=
4702 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004703 get_one_virtual_pixel_from_handler=
4704 cache_info->methods.get_one_virtual_pixel_from_handler;
4705 if (get_one_virtual_pixel_from_handler !=
4706 (GetOneVirtualPixelFromHandler) NULL)
4707 cache_info->methods.get_one_virtual_pixel_from_handler=
4708 cache_methods->get_one_virtual_pixel_from_handler;
4709 get_one_authentic_pixel_from_handler=
4710 cache_methods->get_one_authentic_pixel_from_handler;
4711 if (get_one_authentic_pixel_from_handler !=
4712 (GetOneAuthenticPixelFromHandler) NULL)
4713 cache_info->methods.get_one_authentic_pixel_from_handler=
4714 cache_methods->get_one_authentic_pixel_from_handler;
4715}
4716
4717/*
4718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4719% %
4720% %
4721% %
4722+ S e t P i x e l C a c h e N e x u s P i x e l s %
4723% %
4724% %
4725% %
4726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4727%
4728% SetPixelCacheNexusPixels() defines the region of the cache for the
4729% specified cache nexus.
4730%
4731% The format of the SetPixelCacheNexusPixels() method is:
4732%
cristy4c08aed2011-07-01 19:47:50 +00004733% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004734% const RectangleInfo *region,NexusInfo *nexus_info,
4735% ExceptionInfo *exception)
4736%
4737% A description of each parameter follows:
4738%
4739% o image: the image.
4740%
4741% o region: A pointer to the RectangleInfo structure that defines the
4742% region of this particular cache nexus.
4743%
4744% o nexus_info: the cache nexus to set.
4745%
4746% o exception: return any errors or warnings in this structure.
4747%
4748*/
cristyabd6e372010-09-15 19:11:26 +00004749
4750static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4751 NexusInfo *nexus_info,ExceptionInfo *exception)
4752{
4753 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4754 return(MagickFalse);
4755 nexus_info->mapped=MagickFalse;
cristy7dc8ac52012-01-10 20:14:52 +00004756 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004757 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004758 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004759 {
4760 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004761 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004762 nexus_info->length);
4763 }
cristy4c08aed2011-07-01 19:47:50 +00004764 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004765 {
4766 (void) ThrowMagickException(exception,GetMagickModule(),
4767 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4768 cache_info->filename);
4769 return(MagickFalse);
4770 }
4771 return(MagickTrue);
4772}
4773
cristy4c08aed2011-07-01 19:47:50 +00004774static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004775 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4776{
4777 CacheInfo
4778 *cache_info;
4779
4780 MagickBooleanType
4781 status;
4782
cristy3ed852e2009-09-05 21:47:34 +00004783 MagickSizeType
4784 length,
4785 number_pixels;
4786
cristy3ed852e2009-09-05 21:47:34 +00004787 cache_info=(CacheInfo *) image->cache;
4788 assert(cache_info->signature == MagickSignature);
4789 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004790 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004791 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004792 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004793 {
cristybb503372010-05-27 20:51:26 +00004794 ssize_t
cristybad067a2010-02-15 17:20:55 +00004795 x,
4796 y;
cristy3ed852e2009-09-05 21:47:34 +00004797
cristyeaedf062010-05-29 22:36:02 +00004798 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4799 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004800 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4801 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004802 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004803 ((nexus_info->region.width == cache_info->columns) ||
4804 ((nexus_info->region.width % cache_info->columns) == 0)))))
4805 {
4806 MagickOffsetType
4807 offset;
4808
4809 /*
4810 Pixels are accessed directly from memory.
4811 */
4812 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4813 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004814 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004815 offset;
4816 nexus_info->metacontent=(void *) NULL;
4817 if (cache_info->metacontent_extent != 0)
4818 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4819 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00004820 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004821 }
4822 }
4823 /*
4824 Pixels are stored in a cache region until they are synced to the cache.
4825 */
4826 number_pixels=(MagickSizeType) nexus_info->region.width*
4827 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004828 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004829 if (cache_info->metacontent_extent != 0)
4830 length+=number_pixels*cache_info->metacontent_extent;
4831 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004832 {
4833 nexus_info->length=length;
4834 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4835 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004836 {
4837 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004838 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004839 }
cristy3ed852e2009-09-05 21:47:34 +00004840 }
4841 else
4842 if (nexus_info->length != length)
4843 {
4844 RelinquishCacheNexusPixels(nexus_info);
4845 nexus_info->length=length;
4846 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4847 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004848 {
4849 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004850 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004851 }
cristy3ed852e2009-09-05 21:47:34 +00004852 }
4853 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004854 nexus_info->metacontent=(void *) NULL;
4855 if (cache_info->metacontent_extent != 0)
4856 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004857 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004858 return(nexus_info->pixels);
4859}
4860
4861/*
4862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4863% %
4864% %
4865% %
4866% S e t P i x e l C a c h e V i r t u a l M e t h o d %
4867% %
4868% %
4869% %
4870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871%
4872% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4873% pixel cache and returns the previous setting. A virtual pixel is any pixel
4874% access that is outside the boundaries of the image cache.
4875%
4876% The format of the SetPixelCacheVirtualMethod() method is:
4877%
cristy387430f2012-02-07 13:09:46 +00004878% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4879% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004880%
4881% A description of each parameter follows:
4882%
4883% o image: the image.
4884%
4885% o virtual_pixel_method: choose the type of virtual pixel.
4886%
cristy387430f2012-02-07 13:09:46 +00004887% o exception: return any errors or warnings in this structure.
4888%
cristy3ed852e2009-09-05 21:47:34 +00004889*/
cristy3d4cb882012-02-07 19:11:26 +00004890
4891static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4892 ExceptionInfo *exception)
4893{
4894 CacheInfo
4895 *cache_info;
4896
4897 MagickBooleanType
4898 status;
4899
4900 ssize_t
4901 y;
4902
4903 assert(image != (Image *) NULL);
4904 assert(image->signature == MagickSignature);
4905 if (image->debug != MagickFalse)
4906 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4907 assert(image->cache != (Cache) NULL);
4908 cache_info=(CacheInfo *) image->cache;
4909 assert(cache_info->signature == MagickSignature);
4910 image->matte=MagickTrue;
4911 status=MagickTrue;
4912#if defined(MAGICKCORE_OPENMP_SUPPORT)
4913 #pragma omp parallel for schedule(static,4) shared(status)
4914#endif
4915 for (y=0; y < (ssize_t) image->rows; y++)
4916 {
4917 const int
4918 id = GetOpenMPThreadId();
4919
4920 register Quantum
4921 *restrict q;
4922
4923 register ssize_t
4924 x;
4925
4926 if (status == MagickFalse)
4927 continue;
4928 q=GetAuthenticPixelCacheNexus(image,0,y,image->columns,1,
4929 cache_info->nexus_info[id],exception);
4930 if (q == (Quantum *) NULL)
4931 {
4932 status=MagickFalse;
4933 continue;
4934 }
4935 for (x=0; x < (ssize_t) image->columns; x++)
4936 {
4937 SetPixelAlpha(image,alpha,q);
4938 q+=GetPixelChannels(image);
4939 }
4940 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4941 exception);
4942 }
4943 return(status);
4944}
4945
cristy387430f2012-02-07 13:09:46 +00004946MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4947 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004948{
4949 CacheInfo
4950 *cache_info;
4951
4952 VirtualPixelMethod
4953 method;
4954
4955 assert(image != (Image *) NULL);
4956 assert(image->signature == MagickSignature);
4957 if (image->debug != MagickFalse)
4958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4959 assert(image->cache != (Cache) NULL);
4960 cache_info=(CacheInfo *) image->cache;
4961 assert(cache_info->signature == MagickSignature);
4962 method=cache_info->virtual_pixel_method;
4963 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004964 switch (virtual_pixel_method)
4965 {
4966 case BackgroundVirtualPixelMethod:
4967 {
4968 if ((image->background_color.matte != MagickFalse) &&
4969 (image->matte == MagickFalse))
cristy3d4cb882012-02-07 19:11:26 +00004970 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004971 break;
4972 }
4973 case TransparentVirtualPixelMethod:
4974 {
4975 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00004976 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004977 break;
4978 }
4979 default:
4980 break;
4981 }
cristy3ed852e2009-09-05 21:47:34 +00004982 return(method);
4983}
4984
4985/*
4986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4987% %
4988% %
4989% %
4990+ S y n c A u t h e n t i c P i x e l C a c h e N e x u s %
4991% %
4992% %
4993% %
4994%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4995%
4996% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4997% in-memory or disk cache. The method returns MagickTrue if the pixel region
4998% is synced, otherwise MagickFalse.
4999%
5000% The format of the SyncAuthenticPixelCacheNexus() method is:
5001%
5002% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5003% NexusInfo *nexus_info,ExceptionInfo *exception)
5004%
5005% A description of each parameter follows:
5006%
5007% o image: the image.
5008%
5009% o nexus_info: the cache nexus to sync.
5010%
5011% o exception: return any errors or warnings in this structure.
5012%
5013*/
cristya6577ff2011-09-02 19:54:26 +00005014MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005015 NexusInfo *nexus_info,ExceptionInfo *exception)
5016{
5017 CacheInfo
5018 *cache_info;
5019
5020 MagickBooleanType
5021 status;
5022
5023 /*
5024 Transfer pixels to the cache.
5025 */
5026 assert(image != (Image *) NULL);
5027 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005028 if (image->cache == (Cache) NULL)
5029 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5030 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005031 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005032 if (cache_info->type == UndefinedCache)
5033 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005034 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005035 return(MagickTrue);
5036 assert(cache_info->signature == MagickSignature);
5037 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005038 if ((cache_info->metacontent_extent != 0) &&
5039 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005040 return(MagickFalse);
5041 return(status);
5042}
5043
5044/*
5045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5046% %
5047% %
5048% %
5049+ S y n c A u t h e n t i c P i x e l C a c h e %
5050% %
5051% %
5052% %
5053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5054%
5055% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5056% or disk cache. The method returns MagickTrue if the pixel region is synced,
5057% otherwise MagickFalse.
5058%
5059% The format of the SyncAuthenticPixelsCache() method is:
5060%
5061% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5062% ExceptionInfo *exception)
5063%
5064% A description of each parameter follows:
5065%
5066% o image: the image.
5067%
5068% o exception: return any errors or warnings in this structure.
5069%
5070*/
5071static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5072 ExceptionInfo *exception)
5073{
5074 CacheInfo
5075 *cache_info;
5076
cristy5c9e6f22010-09-17 17:31:01 +00005077 const int
5078 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005079
cristy4c08aed2011-07-01 19:47:50 +00005080 MagickBooleanType
5081 status;
5082
cristye7cc7cf2010-09-21 13:26:47 +00005083 assert(image != (Image *) NULL);
5084 assert(image->signature == MagickSignature);
5085 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005086 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005087 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005088 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005089 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5090 exception);
5091 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005092}
5093
5094/*
5095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5096% %
5097% %
5098% %
5099% S y n c A u t h e n t i c P i x e l s %
5100% %
5101% %
5102% %
5103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5104%
5105% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5106% The method returns MagickTrue if the pixel region is flushed, otherwise
5107% MagickFalse.
5108%
5109% The format of the SyncAuthenticPixels() method is:
5110%
5111% MagickBooleanType SyncAuthenticPixels(Image *image,
5112% ExceptionInfo *exception)
5113%
5114% A description of each parameter follows:
5115%
5116% o image: the image.
5117%
5118% o exception: return any errors or warnings in this structure.
5119%
5120*/
5121MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5122 ExceptionInfo *exception)
5123{
5124 CacheInfo
5125 *cache_info;
5126
cristy2036f5c2010-09-19 21:18:17 +00005127 const int
5128 id = GetOpenMPThreadId();
5129
cristy4c08aed2011-07-01 19:47:50 +00005130 MagickBooleanType
5131 status;
5132
cristy3ed852e2009-09-05 21:47:34 +00005133 assert(image != (Image *) NULL);
5134 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005135 assert(image->cache != (Cache) NULL);
5136 cache_info=(CacheInfo *) image->cache;
5137 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005138 if (cache_info->methods.sync_authentic_pixels_handler !=
5139 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005140 {
5141 status=cache_info->methods.sync_authentic_pixels_handler(image,
5142 exception);
5143 return(status);
5144 }
cristy2036f5c2010-09-19 21:18:17 +00005145 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005146 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5147 exception);
5148 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005149}
5150
5151/*
5152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5153% %
5154% %
5155% %
cristyd1dd6e42011-09-04 01:46:08 +00005156+ S y n c I m a g e P i x e l C a c h e %
cristy6e437132011-08-12 13:02:19 +00005157% %
5158% %
5159% %
5160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5161%
5162% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5163% The method returns MagickTrue if the pixel region is flushed, otherwise
5164% MagickFalse.
5165%
5166% The format of the SyncImagePixelCache() method is:
5167%
5168% MagickBooleanType SyncImagePixelCache(Image *image,
5169% ExceptionInfo *exception)
5170%
5171% A description of each parameter follows:
5172%
5173% o image: the image.
5174%
5175% o exception: return any errors or warnings in this structure.
5176%
5177*/
cristyd1dd6e42011-09-04 01:46:08 +00005178MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005179 ExceptionInfo *exception)
5180{
5181 CacheInfo
5182 *cache_info;
5183
5184 assert(image != (Image *) NULL);
5185 assert(exception != (ExceptionInfo *) NULL);
5186 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5187 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5188}
5189
5190/*
5191%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5192% %
5193% %
5194% %
cristy4c08aed2011-07-01 19:47:50 +00005195+ W r i t e P i x e l C a c h e M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00005196% %
5197% %
5198% %
5199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5200%
cristy4c08aed2011-07-01 19:47:50 +00005201% WritePixelCacheMetacontent() writes the meta-content to the specified region
5202% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005203%
cristy4c08aed2011-07-01 19:47:50 +00005204% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005205%
cristy4c08aed2011-07-01 19:47:50 +00005206% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005207% NexusInfo *nexus_info,ExceptionInfo *exception)
5208%
5209% A description of each parameter follows:
5210%
5211% o cache_info: the pixel cache.
5212%
cristy4c08aed2011-07-01 19:47:50 +00005213% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005214%
5215% o exception: return any errors or warnings in this structure.
5216%
5217*/
cristy4c08aed2011-07-01 19:47:50 +00005218static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005219 NexusInfo *nexus_info,ExceptionInfo *exception)
5220{
5221 MagickOffsetType
5222 count,
5223 offset;
5224
5225 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005226 extent,
5227 length;
cristy3ed852e2009-09-05 21:47:34 +00005228
cristy4c08aed2011-07-01 19:47:50 +00005229 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005230 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005231
cristybb503372010-05-27 20:51:26 +00005232 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005233 y;
5234
cristybb503372010-05-27 20:51:26 +00005235 size_t
cristy3ed852e2009-09-05 21:47:34 +00005236 rows;
5237
cristy4c08aed2011-07-01 19:47:50 +00005238 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005239 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005240 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005241 return(MagickTrue);
5242 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5243 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005244 length=(MagickSizeType) nexus_info->region.width*
5245 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005246 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005247 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005248 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005249 switch (cache_info->type)
5250 {
5251 case MemoryCache:
5252 case MapCache:
5253 {
cristy4c08aed2011-07-01 19:47:50 +00005254 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005255 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005256
5257 /*
cristy4c08aed2011-07-01 19:47:50 +00005258 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005259 */
cristydd341db2010-03-04 19:06:38 +00005260 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005261 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005262 {
cristy48078b12010-09-23 17:11:01 +00005263 length=extent;
cristydd341db2010-03-04 19:06:38 +00005264 rows=1UL;
5265 }
cristy4c08aed2011-07-01 19:47:50 +00005266 q=(unsigned char *) cache_info->metacontent+offset*
5267 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005268 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005269 {
cristy8f036fe2010-09-18 02:02:00 +00005270 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005271 p+=nexus_info->region.width*cache_info->metacontent_extent;
5272 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005273 }
5274 break;
5275 }
5276 case DiskCache:
5277 {
5278 /*
cristy4c08aed2011-07-01 19:47:50 +00005279 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005280 */
5281 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5282 {
5283 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5284 cache_info->cache_filename);
5285 return(MagickFalse);
5286 }
cristydd341db2010-03-04 19:06:38 +00005287 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005288 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005289 {
cristy48078b12010-09-23 17:11:01 +00005290 length=extent;
cristydd341db2010-03-04 19:06:38 +00005291 rows=1UL;
5292 }
cristy48078b12010-09-23 17:11:01 +00005293 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005294 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005295 {
cristy48078b12010-09-23 17:11:01 +00005296 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005297 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005298 cache_info->metacontent_extent,length,(const unsigned char *) p);
5299 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005300 break;
cristy4c08aed2011-07-01 19:47:50 +00005301 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005302 offset+=cache_info->columns;
5303 }
cristyc11dace2012-01-24 16:39:46 +00005304 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5305 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005306 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005307 {
5308 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5309 cache_info->cache_filename);
5310 return(MagickFalse);
5311 }
5312 break;
5313 }
5314 default:
5315 break;
5316 }
5317 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005318 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005319 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005320 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005321 nexus_info->region.width,(double) nexus_info->region.height,(double)
5322 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005323 return(MagickTrue);
5324}
5325
5326/*
5327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5328% %
5329% %
5330% %
5331+ W r i t e C a c h e P i x e l s %
5332% %
5333% %
5334% %
5335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5336%
5337% WritePixelCachePixels() writes image pixels to the specified region of the
5338% pixel cache.
5339%
5340% The format of the WritePixelCachePixels() method is:
5341%
5342% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5343% NexusInfo *nexus_info,ExceptionInfo *exception)
5344%
5345% A description of each parameter follows:
5346%
5347% o cache_info: the pixel cache.
5348%
5349% o nexus_info: the cache nexus to write the pixels.
5350%
5351% o exception: return any errors or warnings in this structure.
5352%
5353*/
5354static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5355 NexusInfo *nexus_info,ExceptionInfo *exception)
5356{
5357 MagickOffsetType
5358 count,
5359 offset;
5360
5361 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005362 extent,
5363 length;
cristy3ed852e2009-09-05 21:47:34 +00005364
cristy4c08aed2011-07-01 19:47:50 +00005365 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005366 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005367
cristybb503372010-05-27 20:51:26 +00005368 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005369 y;
5370
cristybb503372010-05-27 20:51:26 +00005371 size_t
cristy3ed852e2009-09-05 21:47:34 +00005372 rows;
5373
cristy4c08aed2011-07-01 19:47:50 +00005374 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005375 return(MagickTrue);
5376 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5377 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005378 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005379 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005380 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005381 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005382 p=nexus_info->pixels;
5383 switch (cache_info->type)
5384 {
5385 case MemoryCache:
5386 case MapCache:
5387 {
cristy4c08aed2011-07-01 19:47:50 +00005388 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005389 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005390
5391 /*
5392 Write pixels to memory.
5393 */
cristydd341db2010-03-04 19:06:38 +00005394 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005395 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005396 {
cristy48078b12010-09-23 17:11:01 +00005397 length=extent;
cristydd341db2010-03-04 19:06:38 +00005398 rows=1UL;
5399 }
cristyed231572011-07-14 02:18:59 +00005400 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005401 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005402 {
cristy8f036fe2010-09-18 02:02:00 +00005403 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005404 p+=nexus_info->region.width*cache_info->number_channels;
5405 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005406 }
5407 break;
5408 }
5409 case DiskCache:
5410 {
5411 /*
5412 Write pixels to disk.
5413 */
5414 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5415 {
5416 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5417 cache_info->cache_filename);
5418 return(MagickFalse);
5419 }
cristydd341db2010-03-04 19:06:38 +00005420 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005421 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005422 {
cristy48078b12010-09-23 17:11:01 +00005423 length=extent;
cristydd341db2010-03-04 19:06:38 +00005424 rows=1UL;
5425 }
cristybb503372010-05-27 20:51:26 +00005426 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005427 {
5428 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005429 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005430 p);
5431 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005432 break;
cristyed231572011-07-14 02:18:59 +00005433 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005434 offset+=cache_info->columns;
5435 }
cristyc11dace2012-01-24 16:39:46 +00005436 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5437 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005438 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005439 {
5440 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5441 cache_info->cache_filename);
5442 return(MagickFalse);
5443 }
5444 break;
5445 }
5446 default:
5447 break;
5448 }
5449 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005450 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005451 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005452 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005453 nexus_info->region.width,(double) nexus_info->region.height,(double)
5454 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005455 return(MagickTrue);
5456}