blob: 2c9157a4e158b00c4d1f4e6d59eff2196b310cac [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"
cristyadf82722012-05-11 17:34:16 +000057#include "MagickCore/memory-private.h"
cristyd2d11ec2012-03-28 13:53:49 +000058#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000059#include "MagickCore/pixel.h"
60#include "MagickCore/pixel-accessor.h"
61#include "MagickCore/policy.h"
62#include "MagickCore/quantum.h"
63#include "MagickCore/random_.h"
64#include "MagickCore/resource_.h"
65#include "MagickCore/semaphore.h"
66#include "MagickCore/splay-tree.h"
67#include "MagickCore/string_.h"
68#include "MagickCore/string-private.h"
69#include "MagickCore/thread-private.h"
70#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000071#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000072#if defined(MAGICKCORE_ZLIB_DELEGATE)
73#include "zlib.h"
74#endif
75
76/*
cristy30097232010-07-01 02:16:30 +000077 Define declarations.
78*/
79#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
cristyc11dace2012-01-24 16:39:46 +000080#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
81 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
cristy30097232010-07-01 02:16:30 +000082
83/*
cristy3ed852e2009-09-05 21:47:34 +000084 Typedef declarations.
85*/
86typedef struct _MagickModulo
87{
cristybb503372010-05-27 20:51:26 +000088 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000089 quotient,
90 remainder;
91} MagickModulo;
92
93struct _NexusInfo
94{
95 MagickBooleanType
96 mapped;
97
98 RectangleInfo
99 region;
100
101 MagickSizeType
102 length;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000105 *cache,
106 *pixels;
107
cristy4c08aed2011-07-01 19:47:50 +0000108 void
109 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000110
cristybb503372010-05-27 20:51:26 +0000111 size_t
cristy3ed852e2009-09-05 21:47:34 +0000112 signature;
113};
114
115/*
116 Forward declarations.
117*/
118#if defined(__cplusplus) || defined(c_plusplus)
119extern "C" {
120#endif
121
cristy19596d62012-02-19 00:24:59 +0000122static Cache
123 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
124 magick_hot_spot;
125
cristy5bef4cd2012-05-17 18:08:56 +0000126static CacheType
127 GetPixelCacheType(const Image *);
128
cristy4c08aed2011-07-01 19:47:50 +0000129static const Quantum
cristybb503372010-05-27 20:51:26 +0000130 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000131 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000132 *GetVirtualPixelsCache(const Image *);
133
cristy4c08aed2011-07-01 19:47:50 +0000134static const void
135 *GetVirtualMetacontentFromCache(const Image *);
136
cristy3ed852e2009-09-05 21:47:34 +0000137static MagickBooleanType
cristy74ce05d2012-05-06 18:41:18 +0000138 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
139 ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000140 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000141 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000143 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000144 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
145 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000146 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000147 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
148
cristy4c08aed2011-07-01 19:47:50 +0000149static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000150 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
151 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000152 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
153 const size_t,ExceptionInfo *),
cristy265a2b22012-05-11 12:48:50 +0000154 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
155 NexusInfo *,ExceptionInfo *) magick_hot_spot;
cristy3ed852e2009-09-05 21:47:34 +0000156
157#if defined(__cplusplus) || defined(c_plusplus)
158}
159#endif
160
161/*
162 Global declarations.
163*/
164static volatile MagickBooleanType
165 instantiate_cache = MagickFalse;
166
167static SemaphoreInfo
168 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000169
170/*
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172% %
173% %
174% %
175+ A c q u i r e P i x e l C a c h e %
176% %
177% %
178% %
179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180%
181% AcquirePixelCache() acquires a pixel cache.
182%
183% The format of the AcquirePixelCache() method is:
184%
cristybb503372010-05-27 20:51:26 +0000185% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000186%
187% A description of each parameter follows:
188%
189% o number_threads: the number of nexus threads.
190%
191*/
cristya6577ff2011-09-02 19:54:26 +0000192MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000193{
194 CacheInfo
195 *cache_info;
196
cristya64b85d2011-09-14 01:02:31 +0000197 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000198 if (cache_info == (CacheInfo *) NULL)
199 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
200 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
201 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000202 cache_info->mode=IOMode;
cristyc511e882012-04-16 21:11:14 +0000203 cache_info->colorspace=sRGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->file=(-1);
205 cache_info->id=GetMagickThreadId();
206 cache_info->number_threads=number_threads;
207 if (number_threads == 0)
cristyfeeb98d2012-05-09 16:32:12 +0000208 cache_info->number_threads=GetOpenMPMaximumThreads();
cristy3ed852e2009-09-05 21:47:34 +0000209 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
210 if (cache_info->nexus_info == (NexusInfo **) NULL)
211 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000212 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000213 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000214 cache_info->disk_semaphore=AllocateSemaphoreInfo();
215 cache_info->debug=IsEventLogging();
216 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000217 return((Cache ) cache_info);
218}
219
220/*
221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222% %
223% %
224% %
225% A c q u i r e P i x e l C a c h e N e x u s %
226% %
227% %
228% %
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230%
231% AcquirePixelCacheNexus() allocates the NexusInfo structure.
232%
233% The format of the AcquirePixelCacheNexus method is:
234%
cristybb503372010-05-27 20:51:26 +0000235% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000236%
237% A description of each parameter follows:
238%
239% o number_threads: the number of nexus threads.
240%
241*/
cristya6577ff2011-09-02 19:54:26 +0000242MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000243{
cristy3ed852e2009-09-05 21:47:34 +0000244 NexusInfo
245 **nexus_info;
246
cristye076a6e2010-08-15 19:59:43 +0000247 register ssize_t
248 i;
249
cristy64c3edf2012-04-13 18:50:13 +0000250 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000251 sizeof(*nexus_info));
252 if (nexus_info == (NexusInfo **) NULL)
253 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000254 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
255 sizeof(**nexus_info));
256 if (nexus_info[0] == (NexusInfo *) NULL)
257 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
258 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000259 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000260 {
cristye5f87c82012-02-14 12:44:17 +0000261 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000262 nexus_info[i]->signature=MagickSignature;
263 }
264 return(nexus_info);
265}
266
267/*
268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269% %
270% %
271% %
cristyd43a46b2010-01-21 02:13:41 +0000272+ A c q u i r e P i x e l C a c h e P i x e l s %
273% %
274% %
275% %
276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277%
278% AcquirePixelCachePixels() returns the pixels associated with the specified
279% image.
280%
281% The format of the AcquirePixelCachePixels() method is:
282%
283% const void *AcquirePixelCachePixels(const Image *image,
284% MagickSizeType *length,ExceptionInfo *exception)
285%
286% A description of each parameter follows:
287%
288% o image: the image.
289%
290% o length: the pixel cache length.
291%
292% o exception: return any errors or warnings in this structure.
293%
294*/
cristyd1dd6e42011-09-04 01:46:08 +0000295MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000296 MagickSizeType *length,ExceptionInfo *exception)
297{
298 CacheInfo
299 *cache_info;
300
301 assert(image != (const Image *) NULL);
302 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000303 assert(exception != (ExceptionInfo *) NULL);
304 assert(exception->signature == MagickSignature);
305 assert(image->cache != (Cache) NULL);
306 cache_info=(CacheInfo *) image->cache;
307 assert(cache_info->signature == MagickSignature);
308 *length=0;
309 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
310 return((const void *) NULL);
311 *length=cache_info->length;
312 return((const void *) cache_info->pixels);
313}
314
315/*
316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317% %
318% %
319% %
cristyf34a1452009-10-24 22:29:27 +0000320+ C a c h e C o m p o n e n t G e n e s i s %
321% %
322% %
323% %
324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325%
326% CacheComponentGenesis() instantiates the cache component.
327%
328% The format of the CacheComponentGenesis method is:
329%
330% MagickBooleanType CacheComponentGenesis(void)
331%
332*/
cristy5ff4eaf2011-09-03 01:38:02 +0000333MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000334{
cristy165b6092009-10-26 13:52:10 +0000335 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000336 return(MagickTrue);
337}
338
339/*
340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341% %
342% %
343% %
344+ C a c h e C o m p o n e n t T e r m i n u s %
345% %
346% %
347% %
348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349%
350% CacheComponentTerminus() destroys the cache component.
351%
352% The format of the CacheComponentTerminus() method is:
353%
354% CacheComponentTerminus(void)
355%
356*/
cristy5ff4eaf2011-09-03 01:38:02 +0000357MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000358{
cristy18b17442009-10-25 18:36:48 +0000359 if (cache_semaphore == (SemaphoreInfo *) NULL)
360 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000361 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000362 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000363 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000364 DestroySemaphoreInfo(&cache_semaphore);
365}
366
367/*
368%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
369% %
370% %
371% %
cristy3ed852e2009-09-05 21:47:34 +0000372+ C l o n e P i x e l C a c h e %
373% %
374% %
375% %
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377%
378% ClonePixelCache() clones a pixel cache.
379%
380% The format of the ClonePixelCache() method is:
381%
382% Cache ClonePixelCache(const Cache cache)
383%
384% A description of each parameter follows:
385%
386% o cache: the pixel cache.
387%
388*/
cristya6577ff2011-09-02 19:54:26 +0000389MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000390{
391 CacheInfo
392 *clone_info;
393
394 const CacheInfo
395 *cache_info;
396
cristy9f027d12011-09-21 01:17:17 +0000397 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000398 cache_info=(const CacheInfo *) cache;
399 assert(cache_info->signature == MagickSignature);
400 if (cache_info->debug != MagickFalse)
401 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
402 cache_info->filename);
403 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
404 if (clone_info == (Cache) NULL)
405 return((Cache) NULL);
406 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
407 return((Cache ) clone_info);
408}
409
410/*
411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412% %
413% %
414% %
cristy60c44a82009-10-07 00:58:49 +0000415+ 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 +0000416% %
417% %
418% %
419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
420% ClonePixelCachePixels() clones the source pixel cache to the destination
421% cache.
422%
423% The format of the ClonePixelCachePixels() method is:
424%
425% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
426% CacheInfo *source_info,ExceptionInfo *exception)
427%
428% A description of each parameter follows:
429%
430% o cache_info: the pixel cache.
431%
432% o source_info: the source pixel cache.
433%
434% o exception: return any errors or warnings in this structure.
435%
436*/
437
438static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
439{
440 int
441 status;
442
cristy5ee247a2010-02-12 15:42:34 +0000443 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000444 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000445 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000446 {
447 status=close(cache_info->file);
448 cache_info->file=(-1);
449 RelinquishMagickResource(FileResource,1);
450 }
cristyf84a1932010-01-03 18:00:18 +0000451 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000452 return(status == -1 ? MagickFalse : MagickTrue);
453}
454
cristy3ed852e2009-09-05 21:47:34 +0000455static inline MagickSizeType MagickMax(const MagickSizeType x,
456 const MagickSizeType y)
457{
458 if (x > y)
459 return(x);
460 return(y);
461}
462
463static inline MagickSizeType MagickMin(const MagickSizeType x,
464 const MagickSizeType y)
465{
466 if (x < y)
467 return(x);
468 return(y);
469}
470
471static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
472 const MapMode mode)
473{
474 int
475 file;
476
477 /*
478 Open pixel cache on disk.
479 */
cristyf84a1932010-01-03 18:00:18 +0000480 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000481 if (cache_info->file != -1)
482 {
cristyf84a1932010-01-03 18:00:18 +0000483 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000484 return(MagickTrue); /* cache already open */
485 }
cristy3ed852e2009-09-05 21:47:34 +0000486 if (*cache_info->cache_filename == '\0')
487 file=AcquireUniqueFileResource(cache_info->cache_filename);
488 else
489 switch (mode)
490 {
491 case ReadMode:
492 {
cristy18c6c272011-09-23 14:40:37 +0000493 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000494 break;
495 }
496 case WriteMode:
497 {
cristy18c6c272011-09-23 14:40:37 +0000498 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
499 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000500 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000501 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000502 break;
503 }
504 case IOMode:
505 default:
506 {
cristy18c6c272011-09-23 14:40:37 +0000507 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000508 O_EXCL,S_MODE);
509 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000510 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000511 break;
512 }
513 }
514 if (file == -1)
515 {
cristyf84a1932010-01-03 18:00:18 +0000516 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000517 return(MagickFalse);
518 }
519 (void) AcquireMagickResource(FileResource,1);
520 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000521 cache_info->mode=mode;
cristyf84a1932010-01-03 18:00:18 +0000522 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000523 return(MagickTrue);
524}
525
cristyf1832792012-05-08 18:38:18 +0000526static inline MagickOffsetType ReadPixelCacheRegion(
527 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
528 const MagickSizeType length,unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000529{
530 register MagickOffsetType
531 i;
532
533 ssize_t
534 count;
535
536#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000537 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000538 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000539 {
cristyf84a1932010-01-03 18:00:18 +0000540 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000541 return((MagickOffsetType) -1);
542 }
543#endif
544 count=0;
545 for (i=0; i < (MagickOffsetType) length; i+=count)
546 {
547#if !defined(MAGICKCORE_HAVE_PREAD)
548 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
549 (MagickSizeType) SSIZE_MAX));
550#else
551 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000552 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000553#endif
554 if (count > 0)
555 continue;
556 count=0;
557 if (errno != EINTR)
558 {
559 i=(-1);
560 break;
561 }
562 }
563#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000564 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000565#endif
566 return(i);
567}
568
cristyf1832792012-05-08 18:38:18 +0000569static inline MagickOffsetType WritePixelCacheRegion(
570 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
571 const MagickSizeType length,const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000572{
573 register MagickOffsetType
574 i;
575
576 ssize_t
577 count;
578
579#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000580 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000581 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000582 {
cristyf84a1932010-01-03 18:00:18 +0000583 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000584 return((MagickOffsetType) -1);
585 }
586#endif
587 count=0;
588 for (i=0; i < (MagickOffsetType) length; i+=count)
589 {
590#if !defined(MAGICKCORE_HAVE_PWRITE)
591 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
592 (MagickSizeType) SSIZE_MAX));
593#else
594 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000595 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000596#endif
597 if (count > 0)
598 continue;
599 count=0;
600 if (errno != EINTR)
601 {
602 i=(-1);
603 break;
604 }
605 }
606#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000607 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000608#endif
609 return(i);
610}
611
cristy4c08aed2011-07-01 19:47:50 +0000612static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000613 CacheInfo *cache_info,ExceptionInfo *exception)
614{
615 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000616 count;
cristy3ed852e2009-09-05 21:47:34 +0000617
cristy4c08aed2011-07-01 19:47:50 +0000618 register MagickOffsetType
619 i;
cristye076a6e2010-08-15 19:59:43 +0000620
cristybb503372010-05-27 20:51:26 +0000621 size_t
cristy4c08aed2011-07-01 19:47:50 +0000622 length;
cristy3ed852e2009-09-05 21:47:34 +0000623
cristy4c08aed2011-07-01 19:47:50 +0000624 unsigned char
625 *blob;
626
627 /*
628 Clone pixel cache (both caches on disk).
629 */
cristy3ed852e2009-09-05 21:47:34 +0000630 if (cache_info->debug != MagickFalse)
631 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000632 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000633 sizeof(*blob));
634 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000635 {
cristy4c08aed2011-07-01 19:47:50 +0000636 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000637 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000638 cache_info->filename);
639 return(MagickFalse);
640 }
cristy3dedf062011-07-02 14:07:40 +0000641 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000642 {
643 blob=(unsigned char *) RelinquishMagickMemory(blob);
644 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
645 cache_info->cache_filename);
646 return(MagickFalse);
647 }
cristy3dedf062011-07-02 14:07:40 +0000648 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000649 {
650 (void) ClosePixelCacheOnDisk(cache_info);
651 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000652 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
653 clone_info->cache_filename);
654 return(MagickFalse);
655 }
cristy4c08aed2011-07-01 19:47:50 +0000656 count=0;
657 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000658 {
cristy4c08aed2011-07-01 19:47:50 +0000659 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
660 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
661 blob);
662 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000663 {
cristy4c08aed2011-07-01 19:47:50 +0000664 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
665 cache_info->cache_filename);
666 break;
cristy3ed852e2009-09-05 21:47:34 +0000667 }
cristy4c08aed2011-07-01 19:47:50 +0000668 length=(size_t) count;
669 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
670 if ((MagickSizeType) count != length)
671 {
672 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
673 clone_info->cache_filename);
674 break;
675 }
676 }
677 (void) ClosePixelCacheOnDisk(clone_info);
678 (void) ClosePixelCacheOnDisk(cache_info);
679 blob=(unsigned char *) RelinquishMagickMemory(blob);
680 if (i < (MagickOffsetType) cache_info->length)
681 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000682 return(MagickTrue);
683}
684
cristyfd24a062012-01-02 14:46:34 +0000685static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000686 CacheInfo *cache_info,ExceptionInfo *exception)
687{
688 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000689 count;
cristy3ed852e2009-09-05 21:47:34 +0000690
cristy4c08aed2011-07-01 19:47:50 +0000691 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000692 {
cristy3ed852e2009-09-05 21:47:34 +0000693 /*
cristy4c08aed2011-07-01 19:47:50 +0000694 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000695 */
cristy4c08aed2011-07-01 19:47:50 +0000696 if (cache_info->debug != MagickFalse)
697 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
698 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
699 cache_info->length);
700 return(MagickTrue);
701 }
702 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
703 {
704 /*
705 Clone pixel cache (one cache on disk, one in memory).
706 */
707 if (cache_info->debug != MagickFalse)
708 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
709 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000710 {
cristy4c08aed2011-07-01 19:47:50 +0000711 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000712 cache_info->cache_filename);
713 return(MagickFalse);
714 }
cristy4c08aed2011-07-01 19:47:50 +0000715 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
716 cache_info->length,(unsigned char *) clone_info->pixels);
717 (void) ClosePixelCacheOnDisk(cache_info);
718 if ((MagickSizeType) count != cache_info->length)
719 {
720 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
721 cache_info->cache_filename);
722 return(MagickFalse);
723 }
724 return(MagickTrue);
725 }
726 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
727 {
728 /*
729 Clone pixel cache (one cache on disk, one in memory).
730 */
731 if (clone_info->debug != MagickFalse)
732 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
733 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
734 {
735 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
736 clone_info->cache_filename);
737 return(MagickFalse);
738 }
739 count=WritePixelCacheRegion(clone_info,clone_info->offset,
740 clone_info->length,(unsigned char *) cache_info->pixels);
741 (void) ClosePixelCacheOnDisk(clone_info);
742 if ((MagickSizeType) count != clone_info->length)
743 {
744 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
745 clone_info->cache_filename);
746 return(MagickFalse);
747 }
748 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000749 }
750 /*
cristy4c08aed2011-07-01 19:47:50 +0000751 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000752 */
cristy4c08aed2011-07-01 19:47:50 +0000753 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000754}
755
cristyfd24a062012-01-02 14:46:34 +0000756static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000757 CacheInfo *cache_info,ExceptionInfo *exception)
758{
cristy4c08aed2011-07-01 19:47:50 +0000759 MagickBooleanType
760 status;
cristy3ed852e2009-09-05 21:47:34 +0000761
cristy4c08aed2011-07-01 19:47:50 +0000762 MagickOffsetType
763 cache_offset,
764 clone_offset,
765 count;
766
767 register ssize_t
768 x;
769
cristyfd24a062012-01-02 14:46:34 +0000770 register unsigned char
771 *p;
772
cristy4c08aed2011-07-01 19:47:50 +0000773 size_t
cristy3ed852e2009-09-05 21:47:34 +0000774 length;
775
cristy4c08aed2011-07-01 19:47:50 +0000776 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000777 y;
778
cristy4c08aed2011-07-01 19:47:50 +0000779 unsigned char
780 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000781
cristy4c08aed2011-07-01 19:47:50 +0000782 /*
783 Clone pixel cache (unoptimized).
784 */
cristy3ed852e2009-09-05 21:47:34 +0000785 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000786 {
cristy4c08aed2011-07-01 19:47:50 +0000787 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
789 else
790 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
792 else
793 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
794 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
795 else
796 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
797 }
cristyed231572011-07-14 02:18:59 +0000798 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
799 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000800 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000801 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000802 if (blob == (unsigned char *) NULL)
803 {
804 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000805 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000806 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000807 return(MagickFalse);
808 }
cristy4c08aed2011-07-01 19:47:50 +0000809 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
810 cache_offset=0;
811 clone_offset=0;
812 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000813 {
cristy4c08aed2011-07-01 19:47:50 +0000814 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000815 {
cristy4c08aed2011-07-01 19:47:50 +0000816 blob=(unsigned char *) RelinquishMagickMemory(blob);
817 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000818 cache_info->cache_filename);
819 return(MagickFalse);
820 }
cristy4c08aed2011-07-01 19:47:50 +0000821 cache_offset=cache_info->offset;
822 }
823 if (clone_info->type == DiskCache)
824 {
cristy3dedf062011-07-02 14:07:40 +0000825 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000826 {
cristy4c08aed2011-07-01 19:47:50 +0000827 blob=(unsigned char *) RelinquishMagickMemory(blob);
828 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
829 clone_info->cache_filename);
830 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000831 }
cristy4c08aed2011-07-01 19:47:50 +0000832 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000833 }
834 /*
cristy4c08aed2011-07-01 19:47:50 +0000835 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000836 */
cristy4c08aed2011-07-01 19:47:50 +0000837 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000838 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000839 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000840 {
cristy4c08aed2011-07-01 19:47:50 +0000841 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000842 {
cristy9e0719b2011-12-29 03:45:45 +0000843 register ssize_t
844 i;
845
cristy3ed852e2009-09-05 21:47:34 +0000846 /*
cristy4c08aed2011-07-01 19:47:50 +0000847 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000848 */
cristyed231572011-07-14 02:18:59 +0000849 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000850 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000851 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000852 else
853 {
cristyfd24a062012-01-02 14:46:34 +0000854 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000855 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000856 {
cristy4c08aed2011-07-01 19:47:50 +0000857 status=MagickFalse;
858 break;
cristy3ed852e2009-09-05 21:47:34 +0000859 }
860 }
cristy4c08aed2011-07-01 19:47:50 +0000861 cache_offset+=length;
862 if ((y < (ssize_t) clone_info->rows) &&
863 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000864 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
cristy9e0719b2011-12-29 03:45:45 +0000866 PixelChannel
867 channel;
868
869 PixelTrait
870 traits;
871
872 ssize_t
873 offset;
874
cristy4c08aed2011-07-01 19:47:50 +0000875 /*
cristy3b8fe922011-12-29 18:56:23 +0000876 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000877 */
cristy9e0719b2011-12-29 03:45:45 +0000878 channel=clone_info->channel_map[i].channel;
879 traits=cache_info->channel_map[channel].traits;
880 if (traits == UndefinedPixelTrait)
881 {
cristy0f4425e2011-12-31 20:33:02 +0000882 clone_offset+=sizeof(Quantum);
883 continue;
cristy9e0719b2011-12-29 03:45:45 +0000884 }
cristy0f4425e2011-12-31 20:33:02 +0000885 offset=cache_info->channel_map[channel].offset;
886 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000887 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
888 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000889 else
890 {
cristy0f4425e2011-12-31 20:33:02 +0000891 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000892 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000893 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000894 {
cristy0f4425e2011-12-31 20:33:02 +0000895 status=MagickFalse;
896 break;
cristy4c08aed2011-07-01 19:47:50 +0000897 }
898 }
cristy9e0719b2011-12-29 03:45:45 +0000899 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000900 }
901 }
cristyac245f82012-05-05 17:13:57 +0000902 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000903 {
904 /*
905 Set remaining columns as undefined.
906 */
cristy888e6132012-04-23 19:54:54 +0000907 length=clone_info->number_channels*sizeof(Quantum);
908 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
909 for ( ; x < (ssize_t) clone_info->columns; x++)
910 {
911 if (clone_info->type != DiskCache)
912 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
913 blob,length);
914 else
915 {
916 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
917 if ((MagickSizeType) count != length)
918 {
919 status=MagickFalse;
920 break;
cristye04362f2012-04-23 15:33:05 +0000921 }
cristy888e6132012-04-23 19:54:54 +0000922 }
923 clone_offset+=length;
924 }
cristye04362f2012-04-23 15:33:05 +0000925 }
cristy4c08aed2011-07-01 19:47:50 +0000926 }
cristyed231572011-07-14 02:18:59 +0000927 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000928 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
929 for ( ; y < (ssize_t) clone_info->rows; y++)
930 {
931 /*
cristy9e0719b2011-12-29 03:45:45 +0000932 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000933 */
934 for (x=0; x < (ssize_t) clone_info->columns; x++)
935 {
936 if (clone_info->type != DiskCache)
937 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
938 length);
939 else
940 {
941 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
942 if ((MagickSizeType) count != length)
943 {
944 status=MagickFalse;
945 break;
946 }
947 }
948 clone_offset+=length;
949 }
950 }
cristy9e0719b2011-12-29 03:45:45 +0000951 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000952 (clone_info->metacontent_extent != 0))
953 {
954 /*
955 Clone metacontent.
956 */
957 for (y=0; y < (ssize_t) cache_info->rows; y++)
958 {
959 for (x=0; x < (ssize_t) cache_info->columns; x++)
960 {
961 /*
962 Read a set of metacontent.
963 */
964 length=cache_info->metacontent_extent;
965 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000966 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000967 else
968 {
cristyfd24a062012-01-02 14:46:34 +0000969 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000970 if ((MagickSizeType) count != length)
971 {
972 status=MagickFalse;
973 break;
974 }
975 }
976 cache_offset+=length;
977 if ((y < (ssize_t) clone_info->rows) &&
978 (x < (ssize_t) clone_info->columns))
979 {
980 /*
981 Write a set of metacontent.
982 */
983 length=clone_info->metacontent_extent;
984 if (clone_info->type != DiskCache)
985 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000986 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000987 else
988 {
cristyfd24a062012-01-02 14:46:34 +0000989 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000990 if ((MagickSizeType) count != length)
991 {
992 status=MagickFalse;
993 break;
994 }
995 }
996 clone_offset+=length;
997 }
998 }
999 length=clone_info->metacontent_extent;
1000 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1001 for ( ; x < (ssize_t) clone_info->columns; x++)
1002 {
1003 /*
cristy9e0719b2011-12-29 03:45:45 +00001004 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001005 */
1006 if (clone_info->type != DiskCache)
1007 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1008 blob,length);
1009 else
1010 {
cristy208b1002011-08-07 18:51:50 +00001011 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001012 if ((MagickSizeType) count != length)
1013 {
1014 status=MagickFalse;
1015 break;
1016 }
1017 }
1018 clone_offset+=length;
1019 }
1020 }
cristyac245f82012-05-05 17:13:57 +00001021 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001022 {
cristye04362f2012-04-23 15:33:05 +00001023 /*
1024 Set remaining rows as undefined.
1025 */
cristy888e6132012-04-23 19:54:54 +00001026 length=clone_info->metacontent_extent;
1027 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1028 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001029 {
cristy888e6132012-04-23 19:54:54 +00001030 for (x=0; x < (ssize_t) clone_info->columns; x++)
1031 {
1032 if (clone_info->type != DiskCache)
1033 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1034 blob,length);
1035 else
1036 {
1037 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1038 blob);
1039 if ((MagickSizeType) count != length)
1040 {
1041 status=MagickFalse;
1042 break;
1043 }
1044 }
1045 clone_offset+=length;
1046 }
cristye04362f2012-04-23 15:33:05 +00001047 }
cristy4c08aed2011-07-01 19:47:50 +00001048 }
cristy4c08aed2011-07-01 19:47:50 +00001049 }
1050 if (clone_info->type == DiskCache)
1051 (void) ClosePixelCacheOnDisk(clone_info);
1052 if (cache_info->type == DiskCache)
1053 (void) ClosePixelCacheOnDisk(cache_info);
1054 blob=(unsigned char *) RelinquishMagickMemory(blob);
1055 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001056}
1057
1058static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1059 CacheInfo *cache_info,ExceptionInfo *exception)
1060{
cristy3dfccb22011-12-28 21:47:20 +00001061 PixelChannelMap
1062 *p,
1063 *q;
1064
cristy5a7fbfb2010-11-06 16:10:59 +00001065 if (cache_info->type == PingCache)
1066 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001067 p=cache_info->channel_map;
1068 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001069 if ((cache_info->columns == clone_info->columns) &&
1070 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001071 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001072 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001073 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001074 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1075 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001076}
1077
1078/*
1079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1080% %
1081% %
1082% %
1083+ C l o n e P i x e l C a c h e M e t h o d s %
1084% %
1085% %
1086% %
1087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088%
1089% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1090% another.
1091%
1092% The format of the ClonePixelCacheMethods() method is:
1093%
1094% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1095%
1096% A description of each parameter follows:
1097%
1098% o clone: Specifies a pointer to a Cache structure.
1099%
1100% o cache: the pixel cache.
1101%
1102*/
cristya6577ff2011-09-02 19:54:26 +00001103MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001104{
1105 CacheInfo
1106 *cache_info,
1107 *source_info;
1108
1109 assert(clone != (Cache) NULL);
1110 source_info=(CacheInfo *) clone;
1111 assert(source_info->signature == MagickSignature);
1112 if (source_info->debug != MagickFalse)
1113 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1114 source_info->filename);
1115 assert(cache != (Cache) NULL);
1116 cache_info=(CacheInfo *) cache;
1117 assert(cache_info->signature == MagickSignature);
1118 source_info->methods=cache_info->methods;
1119}
1120
1121/*
1122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1123% %
1124% %
1125% %
1126+ D e s t r o y I m a g e P i x e l C a c h e %
1127% %
1128% %
1129% %
1130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1131%
1132% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1133%
1134% The format of the DestroyImagePixelCache() method is:
1135%
1136% void DestroyImagePixelCache(Image *image)
1137%
1138% A description of each parameter follows:
1139%
1140% o image: the image.
1141%
1142*/
1143static void DestroyImagePixelCache(Image *image)
1144{
1145 assert(image != (Image *) NULL);
1146 assert(image->signature == MagickSignature);
1147 if (image->debug != MagickFalse)
1148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1149 if (image->cache == (void *) NULL)
1150 return;
1151 image->cache=DestroyPixelCache(image->cache);
1152}
1153
1154/*
1155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1156% %
1157% %
1158% %
1159+ D e s t r o y I m a g e P i x e l s %
1160% %
1161% %
1162% %
1163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1164%
1165% DestroyImagePixels() deallocates memory associated with the pixel cache.
1166%
1167% The format of the DestroyImagePixels() method is:
1168%
1169% void DestroyImagePixels(Image *image)
1170%
1171% A description of each parameter follows:
1172%
1173% o image: the image.
1174%
1175*/
1176MagickExport void DestroyImagePixels(Image *image)
1177{
1178 CacheInfo
1179 *cache_info;
1180
1181 assert(image != (const Image *) NULL);
1182 assert(image->signature == MagickSignature);
1183 if (image->debug != MagickFalse)
1184 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1185 assert(image->cache != (Cache) NULL);
1186 cache_info=(CacheInfo *) image->cache;
1187 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001188 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1189 {
1190 cache_info->methods.destroy_pixel_handler(image);
1191 return;
1192 }
cristy2036f5c2010-09-19 21:18:17 +00001193 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001194}
1195
1196/*
1197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198% %
1199% %
1200% %
1201+ D e s t r o y P i x e l C a c h e %
1202% %
1203% %
1204% %
1205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206%
1207% DestroyPixelCache() deallocates memory associated with the pixel cache.
1208%
1209% The format of the DestroyPixelCache() method is:
1210%
1211% Cache DestroyPixelCache(Cache cache)
1212%
1213% A description of each parameter follows:
1214%
1215% o cache: the pixel cache.
1216%
1217*/
1218
1219static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1220{
1221 switch (cache_info->type)
1222 {
1223 case MemoryCache:
1224 {
1225 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001226 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001227 cache_info->pixels);
1228 else
cristy4c08aed2011-07-01 19:47:50 +00001229 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001230 (size_t) cache_info->length);
1231 RelinquishMagickResource(MemoryResource,cache_info->length);
1232 break;
1233 }
1234 case MapCache:
1235 {
cristy4c08aed2011-07-01 19:47:50 +00001236 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001237 cache_info->length);
1238 RelinquishMagickResource(MapResource,cache_info->length);
1239 }
1240 case DiskCache:
1241 {
1242 if (cache_info->file != -1)
1243 (void) ClosePixelCacheOnDisk(cache_info);
1244 RelinquishMagickResource(DiskResource,cache_info->length);
1245 break;
1246 }
1247 default:
1248 break;
1249 }
1250 cache_info->type=UndefinedCache;
1251 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001252 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001253}
1254
cristya6577ff2011-09-02 19:54:26 +00001255MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001256{
1257 CacheInfo
1258 *cache_info;
1259
cristy3ed852e2009-09-05 21:47:34 +00001260 assert(cache != (Cache) NULL);
1261 cache_info=(CacheInfo *) cache;
1262 assert(cache_info->signature == MagickSignature);
1263 if (cache_info->debug != MagickFalse)
1264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1265 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001266 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001267 cache_info->reference_count--;
1268 if (cache_info->reference_count != 0)
1269 {
cristyf84a1932010-01-03 18:00:18 +00001270 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001271 return((Cache) NULL);
1272 }
cristyf84a1932010-01-03 18:00:18 +00001273 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001274 if (cache_info->debug != MagickFalse)
1275 {
1276 char
1277 message[MaxTextExtent];
1278
cristyb51dff52011-05-19 16:55:47 +00001279 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001280 cache_info->filename);
1281 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1282 }
cristyc2e1bdd2009-09-10 23:43:34 +00001283 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1284 (cache_info->type != DiskCache)))
1285 RelinquishPixelCachePixels(cache_info);
1286 else
1287 {
1288 RelinquishPixelCachePixels(cache_info);
1289 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1290 }
cristy3ed852e2009-09-05 21:47:34 +00001291 *cache_info->cache_filename='\0';
1292 if (cache_info->nexus_info != (NexusInfo **) NULL)
1293 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1294 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001295 if (cache_info->random_info != (RandomInfo *) NULL)
1296 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001297 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1298 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1299 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1300 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001301 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001302 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001303 cache=(Cache) NULL;
1304 return(cache);
1305}
1306
1307/*
1308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309% %
1310% %
1311% %
1312+ D e s t r o y P i x e l C a c h e N e x u s %
1313% %
1314% %
1315% %
1316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1317%
1318% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1319%
1320% The format of the DestroyPixelCacheNexus() method is:
1321%
1322% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001323% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001324%
1325% A description of each parameter follows:
1326%
1327% o nexus_info: the nexus to destroy.
1328%
1329% o number_threads: the number of nexus threads.
1330%
1331*/
1332
1333static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1334{
1335 if (nexus_info->mapped == MagickFalse)
cristy64c3edf2012-04-13 18:50:13 +00001336 (void) RelinquishMagickMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001337 else
1338 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001339 nexus_info->cache=(Quantum *) NULL;
1340 nexus_info->pixels=(Quantum *) NULL;
1341 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001342 nexus_info->length=0;
1343 nexus_info->mapped=MagickFalse;
1344}
1345
cristya6577ff2011-09-02 19:54:26 +00001346MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001347 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001348{
cristybb503372010-05-27 20:51:26 +00001349 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001350 i;
1351
1352 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001353 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001354 {
cristy4c08aed2011-07-01 19:47:50 +00001355 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001356 RelinquishCacheNexusPixels(nexus_info[i]);
1357 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001358 }
cristye5f87c82012-02-14 12:44:17 +00001359 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001360 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001361 return(nexus_info);
1362}
1363
1364/*
1365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366% %
1367% %
1368% %
cristy4c08aed2011-07-01 19:47:50 +00001369% 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 +00001370% %
1371% %
1372% %
1373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1374%
cristy4c08aed2011-07-01 19:47:50 +00001375% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1376% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1377% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001378%
cristy4c08aed2011-07-01 19:47:50 +00001379% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001380%
cristy4c08aed2011-07-01 19:47:50 +00001381% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001382%
1383% A description of each parameter follows:
1384%
1385% o image: the image.
1386%
1387*/
cristy4c08aed2011-07-01 19:47:50 +00001388MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001389{
1390 CacheInfo
1391 *cache_info;
1392
cristy5c9e6f22010-09-17 17:31:01 +00001393 const int
1394 id = GetOpenMPThreadId();
1395
cristy4c08aed2011-07-01 19:47:50 +00001396 void
1397 *metacontent;
1398
cristye7cc7cf2010-09-21 13:26:47 +00001399 assert(image != (const Image *) NULL);
1400 assert(image->signature == MagickSignature);
1401 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001402 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001403 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001404 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1405 (GetAuthenticMetacontentFromHandler) NULL)
1406 {
1407 metacontent=cache_info->methods.
1408 get_authentic_metacontent_from_handler(image);
1409 return(metacontent);
1410 }
cristy6ebe97c2010-07-03 01:17:28 +00001411 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001412 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1413 cache_info->nexus_info[id]);
1414 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001415}
1416
1417/*
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419% %
1420% %
1421% %
cristy4c08aed2011-07-01 19:47:50 +00001422+ 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 +00001423% %
1424% %
1425% %
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427%
cristy4c08aed2011-07-01 19:47:50 +00001428% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1429% with the last call to QueueAuthenticPixelsCache() or
1430% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001431%
cristy4c08aed2011-07-01 19:47:50 +00001432% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001433%
cristy4c08aed2011-07-01 19:47:50 +00001434% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001435%
1436% A description of each parameter follows:
1437%
1438% o image: the image.
1439%
1440*/
cristy4c08aed2011-07-01 19:47:50 +00001441static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001442{
1443 CacheInfo
1444 *cache_info;
1445
cristy2036f5c2010-09-19 21:18:17 +00001446 const int
1447 id = GetOpenMPThreadId();
1448
cristy4c08aed2011-07-01 19:47:50 +00001449 void
1450 *metacontent;
1451
cristy3ed852e2009-09-05 21:47:34 +00001452 assert(image != (const Image *) NULL);
1453 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001454 assert(image->cache != (Cache) NULL);
1455 cache_info=(CacheInfo *) image->cache;
1456 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001457 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001458 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1459 cache_info->nexus_info[id]);
1460 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001461}
1462
1463/*
1464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465% %
1466% %
1467% %
1468+ 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 %
1469% %
1470% %
1471% %
1472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1473%
1474% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1475% disk pixel cache as defined by the geometry parameters. A pointer to the
1476% pixels is returned if the pixels are transferred, otherwise a NULL is
1477% returned.
1478%
1479% The format of the GetAuthenticPixelCacheNexus() method is:
1480%
cristy4c08aed2011-07-01 19:47:50 +00001481% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001482% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001483% NexusInfo *nexus_info,ExceptionInfo *exception)
1484%
1485% A description of each parameter follows:
1486%
1487% o image: the image.
1488%
1489% o x,y,columns,rows: These values define the perimeter of a region of
1490% pixels.
1491%
1492% o nexus_info: the cache nexus to return.
1493%
1494% o exception: return any errors or warnings in this structure.
1495%
1496*/
1497
cristy7f69b802012-05-08 16:39:59 +00001498static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001499 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001500{
cristy4c08aed2011-07-01 19:47:50 +00001501 MagickBooleanType
1502 status;
1503
cristy3ed852e2009-09-05 21:47:34 +00001504 MagickOffsetType
1505 offset;
1506
cristy73724512010-04-12 14:43:14 +00001507 if (cache_info->type == PingCache)
1508 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001509 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1510 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001511 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001512 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001513 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001514}
1515
cristya6577ff2011-09-02 19:54:26 +00001516MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001517 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001518 NexusInfo *nexus_info,ExceptionInfo *exception)
1519{
1520 CacheInfo
1521 *cache_info;
1522
cristy4c08aed2011-07-01 19:47:50 +00001523 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001524 *q;
cristy3ed852e2009-09-05 21:47:34 +00001525
1526 /*
1527 Transfer pixels from the cache.
1528 */
1529 assert(image != (Image *) NULL);
1530 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001531 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1532 exception);
cristyacd2ed22011-08-30 01:44:23 +00001533 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001534 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001535 cache_info=(CacheInfo *) image->cache;
1536 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001537 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001538 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001539 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001540 return((Quantum *) NULL);
1541 if (cache_info->metacontent_extent != 0)
1542 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1543 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001544 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001545}
1546
1547/*
1548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1549% %
1550% %
1551% %
1552+ 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 %
1553% %
1554% %
1555% %
1556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1557%
1558% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1559% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1560%
1561% The format of the GetAuthenticPixelsFromCache() method is:
1562%
cristy4c08aed2011-07-01 19:47:50 +00001563% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001564%
1565% A description of each parameter follows:
1566%
1567% o image: the image.
1568%
1569*/
cristy4c08aed2011-07-01 19:47:50 +00001570static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001571{
1572 CacheInfo
1573 *cache_info;
1574
cristy5c9e6f22010-09-17 17:31:01 +00001575 const int
1576 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001577
cristye7cc7cf2010-09-21 13:26:47 +00001578 assert(image != (const Image *) NULL);
1579 assert(image->signature == MagickSignature);
1580 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001581 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001582 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001583 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001584 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001585}
1586
1587/*
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589% %
1590% %
1591% %
1592% G e t A u t h e n t i c P i x e l Q u e u e %
1593% %
1594% %
1595% %
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597%
cristy4c08aed2011-07-01 19:47:50 +00001598% GetAuthenticPixelQueue() returns the authentic pixels associated
1599% corresponding with the last call to QueueAuthenticPixels() or
1600% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001601%
1602% The format of the GetAuthenticPixelQueue() method is:
1603%
cristy4c08aed2011-07-01 19:47:50 +00001604% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001605%
1606% A description of each parameter follows:
1607%
1608% o image: the image.
1609%
1610*/
cristy4c08aed2011-07-01 19:47:50 +00001611MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001612{
1613 CacheInfo
1614 *cache_info;
1615
cristy2036f5c2010-09-19 21:18:17 +00001616 const int
1617 id = GetOpenMPThreadId();
1618
cristy3ed852e2009-09-05 21:47:34 +00001619 assert(image != (const Image *) NULL);
1620 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001621 assert(image->cache != (Cache) NULL);
1622 cache_info=(CacheInfo *) image->cache;
1623 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001624 if (cache_info->methods.get_authentic_pixels_from_handler !=
1625 (GetAuthenticPixelsFromHandler) NULL)
1626 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001627 assert(id < (int) cache_info->number_threads);
1628 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001629}
1630
1631/*
1632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633% %
1634% %
1635% %
1636% G e t A u t h e n t i c P i x e l s %
1637% %
1638% %
cristy4c08aed2011-07-01 19:47:50 +00001639% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001640%
1641% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001642% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001643% representing the region is returned, otherwise NULL is returned.
1644%
1645% The returned pointer may point to a temporary working copy of the pixels
1646% or it may point to the original pixels in memory. Performance is maximized
1647% if the selected region is part of one row, or one or more full rows, since
1648% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001649% if the image is in memory, or in a memory-mapped file. The returned pointer
1650% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001651%
1652% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001653% Quantum. If the image has corresponding metacontent,call
1654% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1655% meta-content corresponding to the region. Once the Quantum array has
1656% been updated, the changes must be saved back to the underlying image using
1657% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001658%
1659% The format of the GetAuthenticPixels() method is:
1660%
cristy4c08aed2011-07-01 19:47:50 +00001661% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001662% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001663% ExceptionInfo *exception)
1664%
1665% A description of each parameter follows:
1666%
1667% o image: the image.
1668%
1669% o x,y,columns,rows: These values define the perimeter of a region of
1670% pixels.
1671%
1672% o exception: return any errors or warnings in this structure.
1673%
1674*/
cristy4c08aed2011-07-01 19:47:50 +00001675MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001676 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001677 ExceptionInfo *exception)
1678{
1679 CacheInfo
1680 *cache_info;
1681
cristy2036f5c2010-09-19 21:18:17 +00001682 const int
1683 id = GetOpenMPThreadId();
1684
cristy4c08aed2011-07-01 19:47:50 +00001685 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001686 *q;
cristy4c08aed2011-07-01 19:47:50 +00001687
cristy3ed852e2009-09-05 21:47:34 +00001688 assert(image != (Image *) NULL);
1689 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001690 assert(image->cache != (Cache) NULL);
1691 cache_info=(CacheInfo *) image->cache;
1692 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001693 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001694 (GetAuthenticPixelsHandler) NULL)
1695 {
cristyacd2ed22011-08-30 01:44:23 +00001696 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1697 exception);
1698 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001699 }
cristy2036f5c2010-09-19 21:18:17 +00001700 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001701 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001702 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001703 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001704}
1705
1706/*
1707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1708% %
1709% %
1710% %
1711+ G e t A u t h e n t i c P i x e l s C a c h e %
1712% %
1713% %
1714% %
1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716%
1717% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1718% as defined by the geometry parameters. A pointer to the pixels is returned
1719% if the pixels are transferred, otherwise a NULL is returned.
1720%
1721% The format of the GetAuthenticPixelsCache() method is:
1722%
cristy4c08aed2011-07-01 19:47:50 +00001723% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001724% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001725% ExceptionInfo *exception)
1726%
1727% A description of each parameter follows:
1728%
1729% o image: the image.
1730%
1731% o x,y,columns,rows: These values define the perimeter of a region of
1732% pixels.
1733%
1734% o exception: return any errors or warnings in this structure.
1735%
1736*/
cristy4c08aed2011-07-01 19:47:50 +00001737static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001738 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001739 ExceptionInfo *exception)
1740{
1741 CacheInfo
1742 *cache_info;
1743
cristy5c9e6f22010-09-17 17:31:01 +00001744 const int
1745 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001746
cristy4c08aed2011-07-01 19:47:50 +00001747 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001748 *q;
cristy4c08aed2011-07-01 19:47:50 +00001749
cristye7cc7cf2010-09-21 13:26:47 +00001750 assert(image != (const Image *) NULL);
1751 assert(image->signature == MagickSignature);
1752 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001753 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001754 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001755 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001756 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001757 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001758 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001759 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001760 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001761}
1762
1763/*
1764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765% %
1766% %
1767% %
1768+ G e t I m a g e E x t e n t %
1769% %
1770% %
1771% %
1772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1773%
cristy4c08aed2011-07-01 19:47:50 +00001774% GetImageExtent() returns the extent of the pixels associated corresponding
1775% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001776%
1777% The format of the GetImageExtent() method is:
1778%
1779% MagickSizeType GetImageExtent(const Image *image)
1780%
1781% A description of each parameter follows:
1782%
1783% o image: the image.
1784%
1785*/
1786MagickExport MagickSizeType GetImageExtent(const Image *image)
1787{
1788 CacheInfo
1789 *cache_info;
1790
cristy5c9e6f22010-09-17 17:31:01 +00001791 const int
1792 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001793
cristy3ed852e2009-09-05 21:47:34 +00001794 assert(image != (Image *) NULL);
1795 assert(image->signature == MagickSignature);
1796 if (image->debug != MagickFalse)
1797 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1798 assert(image->cache != (Cache) NULL);
1799 cache_info=(CacheInfo *) image->cache;
1800 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001801 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001802 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001803}
1804
1805/*
1806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807% %
1808% %
1809% %
1810+ G e t I m a g e P i x e l C a c h e %
1811% %
1812% %
1813% %
1814%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1815%
1816% GetImagePixelCache() ensures that there is only a single reference to the
1817% pixel cache to be modified, updating the provided cache pointer to point to
1818% a clone of the original pixel cache if necessary.
1819%
1820% The format of the GetImagePixelCache method is:
1821%
1822% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1823% ExceptionInfo *exception)
1824%
1825% A description of each parameter follows:
1826%
1827% o image: the image.
1828%
1829% o clone: any value other than MagickFalse clones the cache pixels.
1830%
1831% o exception: return any errors or warnings in this structure.
1832%
1833*/
cristyaf894d72011-08-06 23:03:10 +00001834
cristyf1832792012-05-08 18:38:18 +00001835static inline MagickBooleanType ValidatePixelCacheMorphology(
1836 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001837{
cristyf1832792012-05-08 18:38:18 +00001838 const CacheInfo
1839 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001840
cristyf1832792012-05-08 18:38:18 +00001841 const PixelChannelMap
1842 *restrict p,
1843 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001844
cristy3ed852e2009-09-05 21:47:34 +00001845 /*
1846 Does the image match the pixel cache morphology?
1847 */
1848 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001849 p=image->channel_map;
1850 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001851 if ((image->storage_class != cache_info->storage_class) ||
1852 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001853 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001854 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001855 (image->columns != cache_info->columns) ||
1856 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001857 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001858 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001859 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001860 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001861 return(MagickFalse);
1862 return(MagickTrue);
1863}
1864
cristycd01fae2011-08-06 23:52:42 +00001865static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1866 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001867{
1868 CacheInfo
1869 *cache_info;
1870
cristy3ed852e2009-09-05 21:47:34 +00001871 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001872 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001873 status;
1874
cristy50a10922010-02-15 18:35:25 +00001875 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001876 cpu_throttle = 0,
1877 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001878 time_limit = 0;
1879
cristy1ea34962010-07-01 19:49:21 +00001880 static time_t
cristy208b1002011-08-07 18:51:50 +00001881 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001882
cristyc4f9f132010-03-04 18:50:01 +00001883 status=MagickTrue;
1884 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001885 if (cpu_throttle == 0)
1886 {
1887 char
1888 *limit;
1889
1890 /*
1891 Set CPU throttle in milleseconds.
1892 */
1893 cpu_throttle=MagickResourceInfinity;
1894 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1895 if (limit == (char *) NULL)
1896 limit=GetPolicyValue("throttle");
1897 if (limit != (char *) NULL)
1898 {
1899 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1900 limit=DestroyString(limit);
1901 }
1902 }
1903 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1904 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001905 if (time_limit == 0)
1906 {
cristy6ebe97c2010-07-03 01:17:28 +00001907 /*
1908 Set the exire time in seconds.
1909 */
cristy1ea34962010-07-01 19:49:21 +00001910 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001911 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001912 }
1913 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001914 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001915 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001916 assert(image->cache != (Cache) NULL);
1917 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001918 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001919 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001920 {
cristyceb55ee2010-11-06 16:05:49 +00001921 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001922 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001923 {
cristyceb55ee2010-11-06 16:05:49 +00001924 Image
1925 clone_image;
1926
1927 CacheInfo
1928 *clone_info;
1929
1930 /*
1931 Clone pixel cache.
1932 */
1933 clone_image=(*image);
1934 clone_image.semaphore=AllocateSemaphoreInfo();
1935 clone_image.reference_count=1;
1936 clone_image.cache=ClonePixelCache(cache_info);
1937 clone_info=(CacheInfo *) clone_image.cache;
1938 status=OpenPixelCache(&clone_image,IOMode,exception);
1939 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001940 {
cristy5a7fbfb2010-11-06 16:10:59 +00001941 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001942 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001943 if (status != MagickFalse)
1944 {
cristy979bf772011-08-08 00:04:15 +00001945 if (cache_info->mode == ReadMode)
1946 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001947 destroy=MagickTrue;
1948 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001949 }
1950 }
cristyceb55ee2010-11-06 16:05:49 +00001951 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001952 }
cristyceb55ee2010-11-06 16:05:49 +00001953 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001954 }
cristy4320e0e2009-09-10 15:00:08 +00001955 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001956 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001957 if (status != MagickFalse)
1958 {
1959 /*
1960 Ensure the image matches the pixel cache morphology.
1961 */
1962 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001963 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001964 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001965 {
1966 status=OpenPixelCache(image,IOMode,exception);
1967 cache_info=(CacheInfo *) image->cache;
1968 if (cache_info->type == DiskCache)
1969 (void) ClosePixelCacheOnDisk(cache_info);
1970 }
cristy3ed852e2009-09-05 21:47:34 +00001971 }
cristyf84a1932010-01-03 18:00:18 +00001972 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001973 if (status == MagickFalse)
1974 return((Cache) NULL);
1975 return(image->cache);
1976}
1977
1978/*
1979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980% %
1981% %
1982% %
cristyce1fe792012-05-16 15:58:37 +00001983+ G e t I m a g e P i x e l C a c h e T y p e %
1984% %
1985% %
1986% %
1987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988%
1989% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1990% DiskCache, MemoryCache, MapCache, or PingCache.
1991%
1992% The format of the GetImagePixelCacheType() method is:
1993%
cristy5bef4cd2012-05-17 18:08:56 +00001994% CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001995%
1996% A description of each parameter follows:
1997%
1998% o image: the image.
1999%
2000*/
cristy5bef4cd2012-05-17 18:08:56 +00002001MagickExport CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00002002{
cristy5bef4cd2012-05-17 18:08:56 +00002003 return(GetPixelCacheType(image));
cristyce1fe792012-05-16 15:58:37 +00002004}
2005
2006/*
2007%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2008% %
2009% %
2010% %
cristy3ed852e2009-09-05 21:47:34 +00002011% G e t O n e A u t h e n t i c P i x e l %
2012% %
2013% %
2014% %
2015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2016%
2017% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2018% location. The image background color is returned if an error occurs.
2019%
2020% The format of the GetOneAuthenticPixel() method is:
2021%
cristybb503372010-05-27 20:51:26 +00002022% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002023% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002024%
2025% A description of each parameter follows:
2026%
2027% o image: the image.
2028%
2029% o x,y: These values define the location of the pixel to return.
2030%
2031% o pixel: return a pixel at the specified (x,y) location.
2032%
2033% o exception: return any errors or warnings in this structure.
2034%
2035*/
cristyacbbb7c2010-06-30 18:56:48 +00002036MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002037 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002038{
2039 CacheInfo
2040 *cache_info;
2041
cristy4c08aed2011-07-01 19:47:50 +00002042 register Quantum
2043 *q;
cristy2036f5c2010-09-19 21:18:17 +00002044
cristy2ed42f62011-10-02 19:49:57 +00002045 register ssize_t
2046 i;
2047
cristy3ed852e2009-09-05 21:47:34 +00002048 assert(image != (Image *) NULL);
2049 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002050 assert(image->cache != (Cache) NULL);
2051 cache_info=(CacheInfo *) image->cache;
2052 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002053 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002054 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2055 (GetOneAuthenticPixelFromHandler) NULL)
2056 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2057 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002058 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2059 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002060 {
cristy9e0719b2011-12-29 03:45:45 +00002061 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2062 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2063 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2064 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2065 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002066 return(MagickFalse);
2067 }
2068 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2069 {
2070 PixelChannel
2071 channel;
2072
cristye2a912b2011-12-05 20:02:07 +00002073 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002074 pixel[channel]=q[i];
2075 }
cristy2036f5c2010-09-19 21:18:17 +00002076 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002077}
2078
2079/*
2080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2081% %
2082% %
2083% %
2084+ 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 %
2085% %
2086% %
2087% %
2088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2089%
2090% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2091% location. The image background color is returned if an error occurs.
2092%
2093% The format of the GetOneAuthenticPixelFromCache() method is:
2094%
2095% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002096% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002097% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002098%
2099% A description of each parameter follows:
2100%
2101% o image: the image.
2102%
2103% o x,y: These values define the location of the pixel to return.
2104%
2105% o pixel: return a pixel at the specified (x,y) location.
2106%
2107% o exception: return any errors or warnings in this structure.
2108%
2109*/
2110static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002111 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002112{
cristy098f78c2010-09-23 17:28:44 +00002113 CacheInfo
2114 *cache_info;
2115
2116 const int
2117 id = GetOpenMPThreadId();
2118
cristy4c08aed2011-07-01 19:47:50 +00002119 register Quantum
2120 *q;
cristy3ed852e2009-09-05 21:47:34 +00002121
cristy2ed42f62011-10-02 19:49:57 +00002122 register ssize_t
2123 i;
2124
cristy0158a4b2010-09-20 13:59:45 +00002125 assert(image != (const Image *) NULL);
2126 assert(image->signature == MagickSignature);
2127 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002128 cache_info=(CacheInfo *) image->cache;
2129 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002130 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002131 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002132 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2133 exception);
2134 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002135 {
cristy9e0719b2011-12-29 03:45:45 +00002136 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2137 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2138 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2139 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2140 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002141 return(MagickFalse);
2142 }
2143 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2144 {
2145 PixelChannel
2146 channel;
2147
cristye2a912b2011-12-05 20:02:07 +00002148 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002149 pixel[channel]=q[i];
2150 }
cristy3ed852e2009-09-05 21:47:34 +00002151 return(MagickTrue);
2152}
2153
2154/*
2155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2156% %
2157% %
2158% %
cristy3ed852e2009-09-05 21:47:34 +00002159% G e t O n e V i r t u a l P i x e l %
2160% %
2161% %
2162% %
2163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164%
2165% GetOneVirtualPixel() returns a single virtual pixel at the specified
2166% (x,y) location. The image background color is returned if an error occurs.
2167% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2168%
2169% The format of the GetOneVirtualPixel() method is:
2170%
cristybb503372010-05-27 20:51:26 +00002171% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002172% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002173%
2174% A description of each parameter follows:
2175%
2176% o image: the image.
2177%
2178% o x,y: These values define the location of the pixel to return.
2179%
2180% o pixel: return a pixel at the specified (x,y) location.
2181%
2182% o exception: return any errors or warnings in this structure.
2183%
2184*/
2185MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002186 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002187{
cristy3ed852e2009-09-05 21:47:34 +00002188 CacheInfo
2189 *cache_info;
2190
cristy0158a4b2010-09-20 13:59:45 +00002191 const int
2192 id = GetOpenMPThreadId();
2193
cristy4c08aed2011-07-01 19:47:50 +00002194 const Quantum
2195 *p;
cristy2036f5c2010-09-19 21:18:17 +00002196
cristy2ed42f62011-10-02 19:49:57 +00002197 register ssize_t
2198 i;
2199
cristy3ed852e2009-09-05 21:47:34 +00002200 assert(image != (const Image *) NULL);
2201 assert(image->signature == MagickSignature);
2202 assert(image->cache != (Cache) NULL);
2203 cache_info=(CacheInfo *) image->cache;
2204 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002205 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002206 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2207 (GetOneVirtualPixelFromHandler) NULL)
2208 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2209 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002210 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002211 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002212 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002213 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002214 {
cristy9e0719b2011-12-29 03:45:45 +00002215 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2216 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2217 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2218 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2219 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002220 return(MagickFalse);
2221 }
2222 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2223 {
2224 PixelChannel
2225 channel;
2226
cristye2a912b2011-12-05 20:02:07 +00002227 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002228 pixel[channel]=p[i];
2229 }
cristy2036f5c2010-09-19 21:18:17 +00002230 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002231}
2232
2233/*
2234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2235% %
2236% %
2237% %
2238+ 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 %
2239% %
2240% %
2241% %
2242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243%
2244% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2245% specified (x,y) location. The image background color is returned if an
2246% error occurs.
2247%
2248% The format of the GetOneVirtualPixelFromCache() method is:
2249%
2250% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002251% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002252% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002253%
2254% A description of each parameter follows:
2255%
2256% o image: the image.
2257%
2258% o virtual_pixel_method: the virtual pixel method.
2259%
2260% o x,y: These values define the location of the pixel to return.
2261%
2262% o pixel: return a pixel at the specified (x,y) location.
2263%
2264% o exception: return any errors or warnings in this structure.
2265%
2266*/
2267static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002268 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002269 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002270{
cristy0158a4b2010-09-20 13:59:45 +00002271 CacheInfo
2272 *cache_info;
2273
2274 const int
2275 id = GetOpenMPThreadId();
2276
cristy4c08aed2011-07-01 19:47:50 +00002277 const Quantum
2278 *p;
cristy3ed852e2009-09-05 21:47:34 +00002279
cristy2ed42f62011-10-02 19:49:57 +00002280 register ssize_t
2281 i;
2282
cristye7cc7cf2010-09-21 13:26:47 +00002283 assert(image != (const Image *) NULL);
2284 assert(image->signature == MagickSignature);
2285 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002286 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002287 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002288 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002289 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002290 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002291 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002292 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002293 {
cristy9e0719b2011-12-29 03:45:45 +00002294 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2295 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2296 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2297 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2298 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002299 return(MagickFalse);
2300 }
2301 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2302 {
2303 PixelChannel
2304 channel;
2305
cristye2a912b2011-12-05 20:02:07 +00002306 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002307 pixel[channel]=p[i];
2308 }
cristy3ed852e2009-09-05 21:47:34 +00002309 return(MagickTrue);
2310}
2311
2312/*
2313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2314% %
2315% %
2316% %
cristy3aa93752011-12-18 15:54:24 +00002317% G e t O n e V i r t u a l P i x e l I n f o %
2318% %
2319% %
2320% %
2321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2322%
2323% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2324% location. The image background color is returned if an error occurs. If
2325% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2326%
2327% The format of the GetOneVirtualPixelInfo() method is:
2328%
2329% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2330% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2331% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2332%
2333% A description of each parameter follows:
2334%
2335% o image: the image.
2336%
2337% o virtual_pixel_method: the virtual pixel method.
2338%
2339% o x,y: these values define the location of the pixel to return.
2340%
2341% o pixel: return a pixel at the specified (x,y) location.
2342%
2343% o exception: return any errors or warnings in this structure.
2344%
2345*/
2346MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2347 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2348 PixelInfo *pixel,ExceptionInfo *exception)
2349{
2350 CacheInfo
2351 *cache_info;
2352
2353 const int
2354 id = GetOpenMPThreadId();
2355
2356 register const Quantum
2357 *p;
2358
2359 assert(image != (const Image *) NULL);
2360 assert(image->signature == MagickSignature);
2361 assert(image->cache != (Cache) NULL);
2362 cache_info=(CacheInfo *) image->cache;
2363 assert(cache_info->signature == MagickSignature);
2364 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002365 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002366 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2367 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002368 if (p == (const Quantum *) NULL)
2369 return(MagickFalse);
2370 GetPixelInfoPixel(image,p,pixel);
2371 return(MagickTrue);
2372}
2373
2374/*
2375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2376% %
2377% %
2378% %
cristy3ed852e2009-09-05 21:47:34 +00002379+ G e t P i x e l C a c h e C o l o r s p a c e %
2380% %
2381% %
2382% %
2383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2384%
2385% GetPixelCacheColorspace() returns the class type of the pixel cache.
2386%
2387% The format of the GetPixelCacheColorspace() method is:
2388%
2389% Colorspace GetPixelCacheColorspace(Cache cache)
2390%
2391% A description of each parameter follows:
2392%
2393% o cache: the pixel cache.
2394%
2395*/
cristya6577ff2011-09-02 19:54:26 +00002396MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002397{
2398 CacheInfo
2399 *cache_info;
2400
2401 assert(cache != (Cache) NULL);
2402 cache_info=(CacheInfo *) cache;
2403 assert(cache_info->signature == MagickSignature);
2404 if (cache_info->debug != MagickFalse)
2405 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2406 cache_info->filename);
2407 return(cache_info->colorspace);
2408}
2409
2410/*
2411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2412% %
2413% %
2414% %
2415+ G e t P i x e l C a c h e M e t h o d s %
2416% %
2417% %
2418% %
2419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2420%
2421% GetPixelCacheMethods() initializes the CacheMethods structure.
2422%
2423% The format of the GetPixelCacheMethods() method is:
2424%
2425% void GetPixelCacheMethods(CacheMethods *cache_methods)
2426%
2427% A description of each parameter follows:
2428%
2429% o cache_methods: Specifies a pointer to a CacheMethods structure.
2430%
2431*/
cristya6577ff2011-09-02 19:54:26 +00002432MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002433{
2434 assert(cache_methods != (CacheMethods *) NULL);
2435 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2436 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2437 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002438 cache_methods->get_virtual_metacontent_from_handler=
2439 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002440 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2441 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002442 cache_methods->get_authentic_metacontent_from_handler=
2443 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002444 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2445 cache_methods->get_one_authentic_pixel_from_handler=
2446 GetOneAuthenticPixelFromCache;
2447 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2448 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2449 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2450}
2451
2452/*
2453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2454% %
2455% %
2456% %
2457+ G e t P i x e l C a c h e N e x u s E x t e n t %
2458% %
2459% %
2460% %
2461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462%
cristy4c08aed2011-07-01 19:47:50 +00002463% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2464% corresponding with the last call to SetPixelCacheNexusPixels() or
2465% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002466%
2467% The format of the GetPixelCacheNexusExtent() method is:
2468%
2469% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2470% NexusInfo *nexus_info)
2471%
2472% A description of each parameter follows:
2473%
2474% o nexus_info: the nexus info.
2475%
2476*/
cristya6577ff2011-09-02 19:54:26 +00002477MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002478 NexusInfo *nexus_info)
2479{
2480 CacheInfo
2481 *cache_info;
2482
2483 MagickSizeType
2484 extent;
2485
cristy9f027d12011-09-21 01:17:17 +00002486 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002487 cache_info=(CacheInfo *) cache;
2488 assert(cache_info->signature == MagickSignature);
2489 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2490 if (extent == 0)
2491 return((MagickSizeType) cache_info->columns*cache_info->rows);
2492 return(extent);
2493}
2494
2495/*
2496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2497% %
2498% %
2499% %
cristy4c08aed2011-07-01 19:47:50 +00002500+ 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 +00002501% %
2502% %
2503% %
2504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2505%
cristy4c08aed2011-07-01 19:47:50 +00002506% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2507% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002508%
cristy4c08aed2011-07-01 19:47:50 +00002509% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002510%
cristy4c08aed2011-07-01 19:47:50 +00002511% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002512% NexusInfo *nexus_info)
2513%
2514% A description of each parameter follows:
2515%
2516% o cache: the pixel cache.
2517%
cristy4c08aed2011-07-01 19:47:50 +00002518% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002519%
2520*/
cristya6577ff2011-09-02 19:54:26 +00002521MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002522 NexusInfo *nexus_info)
2523{
2524 CacheInfo
2525 *cache_info;
2526
cristy9f027d12011-09-21 01:17:17 +00002527 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002528 cache_info=(CacheInfo *) cache;
2529 assert(cache_info->signature == MagickSignature);
2530 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002531 return((void *) NULL);
2532 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002533}
2534
2535/*
2536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2537% %
2538% %
2539% %
2540+ G e t P i x e l C a c h e N e x u s P i x e l s %
2541% %
2542% %
2543% %
2544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2545%
2546% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2547% cache nexus.
2548%
2549% The format of the GetPixelCacheNexusPixels() method is:
2550%
cristy4c08aed2011-07-01 19:47:50 +00002551% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002552% NexusInfo *nexus_info)
2553%
2554% A description of each parameter follows:
2555%
2556% o cache: the pixel cache.
2557%
2558% o nexus_info: the cache nexus to return the pixels.
2559%
2560*/
cristya6577ff2011-09-02 19:54:26 +00002561MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002562 NexusInfo *nexus_info)
2563{
2564 CacheInfo
2565 *cache_info;
2566
cristy9f027d12011-09-21 01:17:17 +00002567 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002568 cache_info=(CacheInfo *) cache;
2569 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002570 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002571 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002572 return(nexus_info->pixels);
2573}
2574
2575/*
2576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2577% %
2578% %
2579% %
cristy056ba772010-01-02 23:33:54 +00002580+ G e t P i x e l C a c h e P i x e l s %
2581% %
2582% %
2583% %
2584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585%
2586% GetPixelCachePixels() returns the pixels associated with the specified image.
2587%
2588% The format of the GetPixelCachePixels() method is:
2589%
cristyf84a1932010-01-03 18:00:18 +00002590% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2591% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002592%
2593% A description of each parameter follows:
2594%
2595% o image: the image.
2596%
2597% o length: the pixel cache length.
2598%
cristyf84a1932010-01-03 18:00:18 +00002599% o exception: return any errors or warnings in this structure.
2600%
cristy056ba772010-01-02 23:33:54 +00002601*/
cristyd1dd6e42011-09-04 01:46:08 +00002602MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002603 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002604{
2605 CacheInfo
2606 *cache_info;
2607
2608 assert(image != (const Image *) NULL);
2609 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002610 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002611 assert(length != (MagickSizeType *) NULL);
2612 assert(exception != (ExceptionInfo *) NULL);
2613 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002614 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002615 assert(cache_info->signature == MagickSignature);
2616 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002617 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002618 return((void *) NULL);
2619 *length=cache_info->length;
2620 return((void *) cache_info->pixels);
2621}
2622
2623/*
2624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2625% %
2626% %
2627% %
cristyb32b90a2009-09-07 21:45:48 +00002628+ 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 +00002629% %
2630% %
2631% %
2632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633%
2634% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2635%
2636% The format of the GetPixelCacheStorageClass() method is:
2637%
2638% ClassType GetPixelCacheStorageClass(Cache cache)
2639%
2640% A description of each parameter follows:
2641%
2642% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2643%
2644% o cache: the pixel cache.
2645%
2646*/
cristya6577ff2011-09-02 19:54:26 +00002647MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002648{
2649 CacheInfo
2650 *cache_info;
2651
2652 assert(cache != (Cache) NULL);
2653 cache_info=(CacheInfo *) cache;
2654 assert(cache_info->signature == MagickSignature);
2655 if (cache_info->debug != MagickFalse)
2656 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2657 cache_info->filename);
2658 return(cache_info->storage_class);
2659}
2660
2661/*
2662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2663% %
2664% %
2665% %
cristyb32b90a2009-09-07 21:45:48 +00002666+ G e t P i x e l C a c h e T i l e S i z e %
2667% %
2668% %
2669% %
2670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671%
2672% GetPixelCacheTileSize() returns the pixel cache tile size.
2673%
2674% The format of the GetPixelCacheTileSize() method is:
2675%
cristybb503372010-05-27 20:51:26 +00002676% void GetPixelCacheTileSize(const Image *image,size_t *width,
2677% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002678%
2679% A description of each parameter follows:
2680%
2681% o image: the image.
2682%
2683% o width: the optimize cache tile width in pixels.
2684%
2685% o height: the optimize cache tile height in pixels.
2686%
2687*/
cristya6577ff2011-09-02 19:54:26 +00002688MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002689 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002690{
cristy4c08aed2011-07-01 19:47:50 +00002691 CacheInfo
2692 *cache_info;
2693
cristyb32b90a2009-09-07 21:45:48 +00002694 assert(image != (Image *) NULL);
2695 assert(image->signature == MagickSignature);
2696 if (image->debug != MagickFalse)
2697 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002698 cache_info=(CacheInfo *) image->cache;
2699 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002700 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002701 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002702 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002703 *height=(*width);
2704}
2705
2706/*
2707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2708% %
2709% %
2710% %
2711+ G e t P i x e l C a c h e T y p e %
2712% %
2713% %
2714% %
2715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716%
2717% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2718%
2719% The format of the GetPixelCacheType() method is:
2720%
2721% CacheType GetPixelCacheType(const Image *image)
2722%
2723% A description of each parameter follows:
2724%
2725% o image: the image.
2726%
2727*/
cristy5bef4cd2012-05-17 18:08:56 +00002728static CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002729{
2730 CacheInfo
2731 *cache_info;
2732
2733 assert(image != (Image *) NULL);
2734 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002735 assert(image->cache != (Cache) NULL);
2736 cache_info=(CacheInfo *) image->cache;
2737 assert(cache_info->signature == MagickSignature);
2738 return(cache_info->type);
2739}
2740
2741/*
2742%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2743% %
2744% %
2745% %
cristy3ed852e2009-09-05 21:47:34 +00002746+ 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 %
2747% %
2748% %
2749% %
2750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2751%
2752% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2753% pixel cache. A virtual pixel is any pixel access that is outside the
2754% boundaries of the image cache.
2755%
2756% The format of the GetPixelCacheVirtualMethod() method is:
2757%
2758% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2759%
2760% A description of each parameter follows:
2761%
2762% o image: the image.
2763%
2764*/
cristyd1dd6e42011-09-04 01:46:08 +00002765MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002766{
2767 CacheInfo
2768 *cache_info;
2769
2770 assert(image != (Image *) NULL);
2771 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002772 assert(image->cache != (Cache) NULL);
2773 cache_info=(CacheInfo *) image->cache;
2774 assert(cache_info->signature == MagickSignature);
2775 return(cache_info->virtual_pixel_method);
2776}
2777
2778/*
2779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2780% %
2781% %
2782% %
cristy4c08aed2011-07-01 19:47:50 +00002783+ 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 +00002784% %
2785% %
2786% %
2787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2788%
cristy4c08aed2011-07-01 19:47:50 +00002789% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2790% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002791%
cristy4c08aed2011-07-01 19:47:50 +00002792% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002793%
cristy4c08aed2011-07-01 19:47:50 +00002794% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002795%
2796% A description of each parameter follows:
2797%
2798% o image: the image.
2799%
2800*/
cristy4c08aed2011-07-01 19:47:50 +00002801static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002802{
2803 CacheInfo
2804 *cache_info;
2805
cristy5c9e6f22010-09-17 17:31:01 +00002806 const int
2807 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002808
cristy4c08aed2011-07-01 19:47:50 +00002809 const void
2810 *metacontent;
2811
cristye7cc7cf2010-09-21 13:26:47 +00002812 assert(image != (const Image *) NULL);
2813 assert(image->signature == MagickSignature);
2814 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002815 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002816 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002817 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002818 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2819 cache_info->nexus_info[id]);
2820 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002821}
2822
2823/*
2824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2825% %
2826% %
2827% %
cristy4c08aed2011-07-01 19:47:50 +00002828+ 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 +00002829% %
2830% %
2831% %
2832%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2833%
cristy4c08aed2011-07-01 19:47:50 +00002834% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2835% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002836%
cristy4c08aed2011-07-01 19:47:50 +00002837% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002838%
cristy4c08aed2011-07-01 19:47:50 +00002839% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002840% NexusInfo *nexus_info)
2841%
2842% A description of each parameter follows:
2843%
2844% o cache: the pixel cache.
2845%
cristy4c08aed2011-07-01 19:47:50 +00002846% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002847%
2848*/
cristya6577ff2011-09-02 19:54:26 +00002849MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002850 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002851{
2852 CacheInfo
2853 *cache_info;
2854
cristye7cc7cf2010-09-21 13:26:47 +00002855 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002856 cache_info=(CacheInfo *) cache;
2857 assert(cache_info->signature == MagickSignature);
2858 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002859 return((void *) NULL);
2860 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002861}
2862
2863/*
2864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2865% %
2866% %
2867% %
cristy4c08aed2011-07-01 19:47:50 +00002868% 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 +00002869% %
2870% %
2871% %
2872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2873%
cristy4c08aed2011-07-01 19:47:50 +00002874% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2875% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2876% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002877%
cristy4c08aed2011-07-01 19:47:50 +00002878% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002879%
cristy4c08aed2011-07-01 19:47:50 +00002880% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002881%
2882% A description of each parameter follows:
2883%
2884% o image: the image.
2885%
2886*/
cristy4c08aed2011-07-01 19:47:50 +00002887MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002888{
2889 CacheInfo
2890 *cache_info;
2891
cristy2036f5c2010-09-19 21:18:17 +00002892 const int
2893 id = GetOpenMPThreadId();
2894
cristy4c08aed2011-07-01 19:47:50 +00002895 const void
2896 *metacontent;
2897
cristy3ed852e2009-09-05 21:47:34 +00002898 assert(image != (const Image *) NULL);
2899 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002900 assert(image->cache != (Cache) NULL);
2901 cache_info=(CacheInfo *) image->cache;
2902 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002903 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002904 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002905 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002906 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002907 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2908 cache_info->nexus_info[id]);
2909 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002910}
2911
2912/*
2913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2914% %
2915% %
2916% %
2917+ 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 %
2918% %
2919% %
2920% %
2921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2922%
2923% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2924% pixel cache as defined by the geometry parameters. A pointer to the pixels
2925% is returned if the pixels are transferred, otherwise a NULL is returned.
2926%
2927% The format of the GetVirtualPixelsFromNexus() method is:
2928%
cristy4c08aed2011-07-01 19:47:50 +00002929% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002930% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002931% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2932% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002933%
2934% A description of each parameter follows:
2935%
2936% o image: the image.
2937%
2938% o virtual_pixel_method: the virtual pixel method.
2939%
2940% o x,y,columns,rows: These values define the perimeter of a region of
2941% pixels.
2942%
2943% o nexus_info: the cache nexus to acquire.
2944%
2945% o exception: return any errors or warnings in this structure.
2946%
2947*/
2948
cristybb503372010-05-27 20:51:26 +00002949static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002950 DitherMatrix[64] =
2951 {
2952 0, 48, 12, 60, 3, 51, 15, 63,
2953 32, 16, 44, 28, 35, 19, 47, 31,
2954 8, 56, 4, 52, 11, 59, 7, 55,
2955 40, 24, 36, 20, 43, 27, 39, 23,
2956 2, 50, 14, 62, 1, 49, 13, 61,
2957 34, 18, 46, 30, 33, 17, 45, 29,
2958 10, 58, 6, 54, 9, 57, 5, 53,
2959 42, 26, 38, 22, 41, 25, 37, 21
2960 };
2961
cristybb503372010-05-27 20:51:26 +00002962static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002963{
cristybb503372010-05-27 20:51:26 +00002964 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002965 index;
2966
2967 index=x+DitherMatrix[x & 0x07]-32L;
2968 if (index < 0L)
2969 return(0L);
cristybb503372010-05-27 20:51:26 +00002970 if (index >= (ssize_t) columns)
2971 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002972 return(index);
2973}
2974
cristybb503372010-05-27 20:51:26 +00002975static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002976{
cristybb503372010-05-27 20:51:26 +00002977 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002978 index;
2979
2980 index=y+DitherMatrix[y & 0x07]-32L;
2981 if (index < 0L)
2982 return(0L);
cristybb503372010-05-27 20:51:26 +00002983 if (index >= (ssize_t) rows)
2984 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002985 return(index);
2986}
2987
cristybb503372010-05-27 20:51:26 +00002988static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002989{
2990 if (x < 0L)
2991 return(0L);
cristybb503372010-05-27 20:51:26 +00002992 if (x >= (ssize_t) columns)
2993 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002994 return(x);
2995}
2996
cristybb503372010-05-27 20:51:26 +00002997static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002998{
2999 if (y < 0L)
3000 return(0L);
cristybb503372010-05-27 20:51:26 +00003001 if (y >= (ssize_t) rows)
3002 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003003 return(y);
3004}
3005
cristybb503372010-05-27 20:51:26 +00003006static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003007{
cristybb503372010-05-27 20:51:26 +00003008 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003009}
3010
cristybb503372010-05-27 20:51:26 +00003011static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003012{
cristybb503372010-05-27 20:51:26 +00003013 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003014}
3015
cristybb503372010-05-27 20:51:26 +00003016static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3017 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003018{
3019 MagickModulo
3020 modulo;
3021
cristy6162bb42011-07-18 11:34:09 +00003022 /*
3023 Compute the remainder of dividing offset by extent. It returns not only
3024 the quotient (tile the offset falls in) but also the positive remainer
3025 within that tile such that 0 <= remainder < extent. This method is
3026 essentially a ldiv() using a floored modulo division rather than the
3027 normal default truncated modulo division.
3028 */
cristybb503372010-05-27 20:51:26 +00003029 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003030 if (offset < 0L)
3031 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003032 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003033 return(modulo);
3034}
3035
cristya6577ff2011-09-02 19:54:26 +00003036MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003037 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3038 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003039 ExceptionInfo *exception)
3040{
3041 CacheInfo
3042 *cache_info;
3043
3044 MagickOffsetType
3045 offset;
3046
3047 MagickSizeType
3048 length,
3049 number_pixels;
3050
3051 NexusInfo
3052 **virtual_nexus;
3053
cristy4c08aed2011-07-01 19:47:50 +00003054 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003055 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003056 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003057
3058 RectangleInfo
3059 region;
3060
cristy4c08aed2011-07-01 19:47:50 +00003061 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003062 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003063
cristy4c08aed2011-07-01 19:47:50 +00003064 register const void
3065 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003066
cristy4c08aed2011-07-01 19:47:50 +00003067 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003068 *restrict q;
3069
cristybb503372010-05-27 20:51:26 +00003070 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003071 i,
3072 u;
cristy3ed852e2009-09-05 21:47:34 +00003073
cristy4c08aed2011-07-01 19:47:50 +00003074 register unsigned char
3075 *restrict s;
3076
cristy105ba3c2011-07-18 02:28:38 +00003077 ssize_t
3078 v;
3079
cristy4c08aed2011-07-01 19:47:50 +00003080 void
cristy105ba3c2011-07-18 02:28:38 +00003081 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003082
cristy3ed852e2009-09-05 21:47:34 +00003083 /*
3084 Acquire pixels.
3085 */
cristye7cc7cf2010-09-21 13:26:47 +00003086 assert(image != (const Image *) NULL);
3087 assert(image->signature == MagickSignature);
3088 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003089 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003090 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003091 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003092 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003093 region.x=x;
3094 region.y=y;
3095 region.width=columns;
3096 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003097 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003098 if (pixels == (Quantum *) NULL)
3099 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003100 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003101 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3102 nexus_info->region.x;
3103 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3104 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003105 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3106 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003107 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3108 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003109 {
3110 MagickBooleanType
3111 status;
3112
3113 /*
3114 Pixel request is inside cache extents.
3115 */
cristy4c08aed2011-07-01 19:47:50 +00003116 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003117 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003118 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3119 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003120 return((const Quantum *) NULL);
3121 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003122 {
cristy4c08aed2011-07-01 19:47:50 +00003123 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003124 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003125 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003126 }
cristyacd2ed22011-08-30 01:44:23 +00003127 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003128 }
3129 /*
3130 Pixel request is outside cache extents.
3131 */
cristy4c08aed2011-07-01 19:47:50 +00003132 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003133 virtual_nexus=AcquirePixelCacheNexus(1);
3134 if (virtual_nexus == (NexusInfo **) NULL)
3135 {
cristy4c08aed2011-07-01 19:47:50 +00003136 if (virtual_nexus != (NexusInfo **) NULL)
3137 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003138 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003139 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003140 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003141 }
cristy105ba3c2011-07-18 02:28:38 +00003142 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3143 sizeof(*virtual_pixel));
3144 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003145 switch (virtual_pixel_method)
3146 {
cristy4c08aed2011-07-01 19:47:50 +00003147 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003148 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003149 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003150 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003151 case MaskVirtualPixelMethod:
3152 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003153 case EdgeVirtualPixelMethod:
3154 case CheckerTileVirtualPixelMethod:
3155 case HorizontalTileVirtualPixelMethod:
3156 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003157 {
cristy4c08aed2011-07-01 19:47:50 +00003158 if (cache_info->metacontent_extent != 0)
3159 {
cristy6162bb42011-07-18 11:34:09 +00003160 /*
3161 Acquire a metacontent buffer.
3162 */
cristya64b85d2011-09-14 01:02:31 +00003163 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003164 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003165 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003166 {
cristy4c08aed2011-07-01 19:47:50 +00003167 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3168 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003169 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003170 return((const Quantum *) NULL);
3171 }
cristy105ba3c2011-07-18 02:28:38 +00003172 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003173 cache_info->metacontent_extent);
3174 }
3175 switch (virtual_pixel_method)
3176 {
3177 case BlackVirtualPixelMethod:
3178 {
cristy30301712011-07-18 15:06:51 +00003179 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3180 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003181 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3182 break;
3183 }
3184 case GrayVirtualPixelMethod:
3185 {
cristy30301712011-07-18 15:06:51 +00003186 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003187 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3188 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003189 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3190 break;
3191 }
3192 case TransparentVirtualPixelMethod:
3193 {
cristy30301712011-07-18 15:06:51 +00003194 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3195 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003196 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3197 break;
3198 }
3199 case MaskVirtualPixelMethod:
3200 case WhiteVirtualPixelMethod:
3201 {
cristy30301712011-07-18 15:06:51 +00003202 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3203 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003204 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3205 break;
3206 }
3207 default:
3208 {
cristy9e0719b2011-12-29 03:45:45 +00003209 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3210 virtual_pixel);
3211 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3212 virtual_pixel);
3213 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3214 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003215 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3216 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003217 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3218 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003219 break;
3220 }
3221 }
cristy3ed852e2009-09-05 21:47:34 +00003222 break;
3223 }
3224 default:
cristy3ed852e2009-09-05 21:47:34 +00003225 break;
cristy3ed852e2009-09-05 21:47:34 +00003226 }
cristybb503372010-05-27 20:51:26 +00003227 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003228 {
cristybb503372010-05-27 20:51:26 +00003229 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003230 {
3231 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003232 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003233 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3234 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003235 {
3236 MagickModulo
3237 x_modulo,
3238 y_modulo;
3239
3240 /*
3241 Transfer a single pixel.
3242 */
3243 length=(MagickSizeType) 1;
3244 switch (virtual_pixel_method)
3245 {
cristy3ed852e2009-09-05 21:47:34 +00003246 default:
3247 {
3248 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003249 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003250 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003251 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003252 break;
3253 }
3254 case RandomVirtualPixelMethod:
3255 {
3256 if (cache_info->random_info == (RandomInfo *) NULL)
3257 cache_info->random_info=AcquireRandomInfo();
3258 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003259 RandomX(cache_info->random_info,cache_info->columns),
3260 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003261 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003262 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003263 break;
3264 }
3265 case DitherVirtualPixelMethod:
3266 {
3267 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003268 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003269 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003270 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003271 break;
3272 }
3273 case TileVirtualPixelMethod:
3274 {
3275 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3276 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3277 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003278 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003279 exception);
cristy4c08aed2011-07-01 19:47:50 +00003280 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003281 break;
3282 }
3283 case MirrorVirtualPixelMethod:
3284 {
3285 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3286 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003287 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003288 x_modulo.remainder-1L;
3289 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3290 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003291 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003292 y_modulo.remainder-1L;
3293 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003294 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003295 exception);
cristy4c08aed2011-07-01 19:47:50 +00003296 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003297 break;
3298 }
3299 case HorizontalTileEdgeVirtualPixelMethod:
3300 {
3301 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3302 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003303 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003304 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003305 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003306 break;
3307 }
3308 case VerticalTileEdgeVirtualPixelMethod:
3309 {
3310 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3311 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003312 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003313 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003314 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3315 break;
3316 }
3317 case BackgroundVirtualPixelMethod:
3318 case BlackVirtualPixelMethod:
3319 case GrayVirtualPixelMethod:
3320 case TransparentVirtualPixelMethod:
3321 case MaskVirtualPixelMethod:
3322 case WhiteVirtualPixelMethod:
3323 {
3324 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003325 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003326 break;
3327 }
3328 case EdgeVirtualPixelMethod:
3329 case CheckerTileVirtualPixelMethod:
3330 {
3331 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3332 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3333 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3334 {
3335 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003336 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003337 break;
3338 }
3339 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3340 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3341 exception);
3342 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3343 break;
3344 }
3345 case HorizontalTileVirtualPixelMethod:
3346 {
3347 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3348 {
3349 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003350 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003351 break;
3352 }
3353 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3354 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3355 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3356 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3357 exception);
3358 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3359 break;
3360 }
3361 case VerticalTileVirtualPixelMethod:
3362 {
3363 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3364 {
3365 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003366 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003367 break;
3368 }
3369 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3370 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3371 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3372 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3373 exception);
3374 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003375 break;
3376 }
3377 }
cristy4c08aed2011-07-01 19:47:50 +00003378 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003379 break;
cristyed231572011-07-14 02:18:59 +00003380 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003381 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003382 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003383 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003384 {
3385 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3386 s+=cache_info->metacontent_extent;
3387 }
cristy3ed852e2009-09-05 21:47:34 +00003388 continue;
3389 }
3390 /*
3391 Transfer a run of pixels.
3392 */
cristy4c08aed2011-07-01 19:47:50 +00003393 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3394 length,1UL,*virtual_nexus,exception);
3395 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003396 break;
cristy4c08aed2011-07-01 19:47:50 +00003397 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003398 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3399 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003400 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003401 {
cristy4c08aed2011-07-01 19:47:50 +00003402 (void) memcpy(s,r,(size_t) length);
3403 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003404 }
3405 }
3406 }
cristy4c08aed2011-07-01 19:47:50 +00003407 /*
3408 Free resources.
3409 */
cristy105ba3c2011-07-18 02:28:38 +00003410 if (virtual_metacontent != (void *) NULL)
3411 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003412 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3413 return(pixels);
3414}
3415
3416/*
3417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3418% %
3419% %
3420% %
3421+ G e t V i r t u a l P i x e l C a c h e %
3422% %
3423% %
3424% %
3425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3426%
3427% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3428% cache as defined by the geometry parameters. A pointer to the pixels
3429% is returned if the pixels are transferred, otherwise a NULL is returned.
3430%
3431% The format of the GetVirtualPixelCache() method is:
3432%
cristy4c08aed2011-07-01 19:47:50 +00003433% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003434% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3435% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003436% ExceptionInfo *exception)
3437%
3438% A description of each parameter follows:
3439%
3440% o image: the image.
3441%
3442% o virtual_pixel_method: the virtual pixel method.
3443%
3444% o x,y,columns,rows: These values define the perimeter of a region of
3445% pixels.
3446%
3447% o exception: return any errors or warnings in this structure.
3448%
3449*/
cristy4c08aed2011-07-01 19:47:50 +00003450static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003451 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3452 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003453{
3454 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003455 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003456
cristy5c9e6f22010-09-17 17:31:01 +00003457 const int
3458 id = GetOpenMPThreadId();
3459
cristy4c08aed2011-07-01 19:47:50 +00003460 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003461 *p;
cristy4c08aed2011-07-01 19:47:50 +00003462
cristye7cc7cf2010-09-21 13:26:47 +00003463 assert(image != (const Image *) NULL);
3464 assert(image->signature == MagickSignature);
3465 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003466 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003467 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003468 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003469 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003470 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003471 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003472}
3473
3474/*
3475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3476% %
3477% %
3478% %
3479% G e t V i r t u a l P i x e l Q u e u e %
3480% %
3481% %
3482% %
3483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3484%
cristy4c08aed2011-07-01 19:47:50 +00003485% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3486% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003487%
3488% The format of the GetVirtualPixelQueue() method is:
3489%
cristy4c08aed2011-07-01 19:47:50 +00003490% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003491%
3492% A description of each parameter follows:
3493%
3494% o image: the image.
3495%
3496*/
cristy4c08aed2011-07-01 19:47:50 +00003497MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003498{
3499 CacheInfo
3500 *cache_info;
3501
cristy2036f5c2010-09-19 21:18:17 +00003502 const int
3503 id = GetOpenMPThreadId();
3504
cristy3ed852e2009-09-05 21:47:34 +00003505 assert(image != (const Image *) NULL);
3506 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003507 assert(image->cache != (Cache) NULL);
3508 cache_info=(CacheInfo *) image->cache;
3509 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003510 if (cache_info->methods.get_virtual_pixels_handler !=
3511 (GetVirtualPixelsHandler) NULL)
3512 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003513 assert(id < (int) cache_info->number_threads);
3514 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003515}
3516
3517/*
3518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3519% %
3520% %
3521% %
3522% G e t V i r t u a l P i x e l s %
3523% %
3524% %
3525% %
3526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3527%
3528% GetVirtualPixels() returns an immutable pixel region. If the
3529% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003530% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003531% copy of the pixels or it may point to the original pixels in memory.
3532% Performance is maximized if the selected region is part of one row, or one
3533% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003534% (without a copy) if the image is in memory, or in a memory-mapped file. The
3535% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003536%
3537% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003538% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3539% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3540% access the meta-content (of type void) corresponding to the the
3541% region.
cristy3ed852e2009-09-05 21:47:34 +00003542%
3543% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3544%
3545% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3546% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3547% GetCacheViewAuthenticPixels() instead.
3548%
3549% The format of the GetVirtualPixels() method is:
3550%
cristy4c08aed2011-07-01 19:47:50 +00003551% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003552% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003553% ExceptionInfo *exception)
3554%
3555% A description of each parameter follows:
3556%
3557% o image: the image.
3558%
3559% o x,y,columns,rows: These values define the perimeter of a region of
3560% pixels.
3561%
3562% o exception: return any errors or warnings in this structure.
3563%
3564*/
cristy4c08aed2011-07-01 19:47:50 +00003565MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003566 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3567 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003568{
3569 CacheInfo
3570 *cache_info;
3571
cristy2036f5c2010-09-19 21:18:17 +00003572 const int
3573 id = GetOpenMPThreadId();
3574
cristy4c08aed2011-07-01 19:47:50 +00003575 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003576 *p;
cristy4c08aed2011-07-01 19:47:50 +00003577
cristy3ed852e2009-09-05 21:47:34 +00003578 assert(image != (const Image *) NULL);
3579 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003580 assert(image->cache != (Cache) NULL);
3581 cache_info=(CacheInfo *) image->cache;
3582 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003583 if (cache_info->methods.get_virtual_pixel_handler !=
3584 (GetVirtualPixelHandler) NULL)
3585 return(cache_info->methods.get_virtual_pixel_handler(image,
3586 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003587 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003588 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003589 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003590 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003591}
3592
3593/*
3594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3595% %
3596% %
3597% %
3598+ 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 %
3599% %
3600% %
3601% %
3602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3603%
cristy4c08aed2011-07-01 19:47:50 +00003604% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3605% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003606%
3607% The format of the GetVirtualPixelsCache() method is:
3608%
cristy4c08aed2011-07-01 19:47:50 +00003609% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003610%
3611% A description of each parameter follows:
3612%
3613% o image: the image.
3614%
3615*/
cristy4c08aed2011-07-01 19:47:50 +00003616static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003617{
3618 CacheInfo
3619 *cache_info;
3620
cristy5c9e6f22010-09-17 17:31:01 +00003621 const int
3622 id = GetOpenMPThreadId();
3623
cristye7cc7cf2010-09-21 13:26:47 +00003624 assert(image != (const Image *) NULL);
3625 assert(image->signature == MagickSignature);
3626 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003627 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003628 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003629 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003630 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003631}
3632
3633/*
3634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3635% %
3636% %
3637% %
3638+ G e t V i r t u a l P i x e l s N e x u s %
3639% %
3640% %
3641% %
3642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3643%
3644% GetVirtualPixelsNexus() returns the pixels associated with the specified
3645% cache nexus.
3646%
3647% The format of the GetVirtualPixelsNexus() method is:
3648%
cristy4c08aed2011-07-01 19:47:50 +00003649% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003650% NexusInfo *nexus_info)
3651%
3652% A description of each parameter follows:
3653%
3654% o cache: the pixel cache.
3655%
3656% o nexus_info: the cache nexus to return the colormap pixels.
3657%
3658*/
cristya6577ff2011-09-02 19:54:26 +00003659MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003660 NexusInfo *nexus_info)
3661{
3662 CacheInfo
3663 *cache_info;
3664
cristye7cc7cf2010-09-21 13:26:47 +00003665 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003666 cache_info=(CacheInfo *) cache;
3667 assert(cache_info->signature == MagickSignature);
3668 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003669 return((Quantum *) NULL);
3670 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003671}
3672
3673/*
3674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3675% %
3676% %
3677% %
cristy3ed852e2009-09-05 21:47:34 +00003678+ O p e n P i x e l C a c h e %
3679% %
3680% %
3681% %
3682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3683%
3684% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3685% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003686% metacontent, and memory mapping the cache if it is disk based. The cache
3687% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003688%
3689% The format of the OpenPixelCache() method is:
3690%
3691% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3692% ExceptionInfo *exception)
3693%
3694% A description of each parameter follows:
3695%
3696% o image: the image.
3697%
3698% o mode: ReadMode, WriteMode, or IOMode.
3699%
3700% o exception: return any errors or warnings in this structure.
3701%
3702*/
3703
cristyd43a46b2010-01-21 02:13:41 +00003704static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003705{
3706 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003707 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003708 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003709 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003710 {
3711 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003712 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003713 cache_info->length);
3714 }
3715}
3716
3717static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3718{
3719 CacheInfo
3720 *cache_info;
3721
3722 MagickOffsetType
3723 count,
3724 extent,
3725 offset;
3726
3727 cache_info=(CacheInfo *) image->cache;
3728 if (image->debug != MagickFalse)
3729 {
3730 char
3731 format[MaxTextExtent],
3732 message[MaxTextExtent];
3733
cristyb9080c92009-12-01 20:13:26 +00003734 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003735 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003736 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003737 cache_info->cache_filename,cache_info->file,format);
3738 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3739 }
3740 if (length != (MagickSizeType) ((MagickOffsetType) length))
3741 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003742 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003743 if (extent < 0)
3744 return(MagickFalse);
3745 if ((MagickSizeType) extent >= length)
3746 return(MagickTrue);
3747 offset=(MagickOffsetType) length-1;
3748 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3749 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3750}
3751
3752static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3753 ExceptionInfo *exception)
3754{
cristy3ed852e2009-09-05 21:47:34 +00003755 CacheInfo
3756 *cache_info,
3757 source_info;
3758
cristyf3a6a9d2010-11-07 21:02:56 +00003759 char
3760 format[MaxTextExtent],
3761 message[MaxTextExtent];
3762
cristy4c08aed2011-07-01 19:47:50 +00003763 MagickBooleanType
3764 status;
3765
cristy3ed852e2009-09-05 21:47:34 +00003766 MagickSizeType
3767 length,
3768 number_pixels;
3769
cristy3ed852e2009-09-05 21:47:34 +00003770 size_t
cristye076a6e2010-08-15 19:59:43 +00003771 columns,
cristy3ed852e2009-09-05 21:47:34 +00003772 packet_size;
3773
cristye7cc7cf2010-09-21 13:26:47 +00003774 assert(image != (const Image *) NULL);
3775 assert(image->signature == MagickSignature);
3776 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003777 if (image->debug != MagickFalse)
3778 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3779 if ((image->columns == 0) || (image->rows == 0))
3780 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3781 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003782 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003783 source_info=(*cache_info);
3784 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003785 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003786 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003787 cache_info->storage_class=image->storage_class;
3788 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003789 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003790 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003791 cache_info->rows=image->rows;
3792 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003793 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003794 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003795 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3796 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003797 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003798 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003799 if (image->ping != MagickFalse)
3800 {
cristy73724512010-04-12 14:43:14 +00003801 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003802 cache_info->pixels=(Quantum *) NULL;
3803 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003804 cache_info->length=0;
3805 return(MagickTrue);
3806 }
cristy3ed852e2009-09-05 21:47:34 +00003807 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003808 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003809 if (image->metacontent_extent != 0)
3810 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003811 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003812 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003813 if (cache_info->columns != columns)
3814 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3815 image->filename);
3816 cache_info->length=length;
3817 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003818 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003819 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003820 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3821 {
3822 status=AcquireMagickResource(MemoryResource,cache_info->length);
3823 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3824 (cache_info->type == MemoryCache))
3825 {
cristyd43a46b2010-01-21 02:13:41 +00003826 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003827 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003828 cache_info->pixels=source_info.pixels;
3829 else
3830 {
3831 /*
3832 Create memory pixel cache.
3833 */
cristy4c08aed2011-07-01 19:47:50 +00003834 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003835 if (image->debug != MagickFalse)
3836 {
cristy32cacff2011-12-31 03:36:27 +00003837 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003838 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003839 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3840 cache_info->filename,cache_info->mapped != MagickFalse ?
3841 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003842 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003843 format);
cristy3ed852e2009-09-05 21:47:34 +00003844 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3845 message);
3846 }
cristy3ed852e2009-09-05 21:47:34 +00003847 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003848 cache_info->metacontent=(void *) NULL;
3849 if (cache_info->metacontent_extent != 0)
3850 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003851 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003852 if ((source_info.storage_class != UndefinedClass) &&
3853 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003854 {
cristy4c08aed2011-07-01 19:47:50 +00003855 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003856 exception);
3857 RelinquishPixelCachePixels(&source_info);
3858 }
cristy4c08aed2011-07-01 19:47:50 +00003859 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003860 }
3861 }
3862 RelinquishMagickResource(MemoryResource,cache_info->length);
3863 }
3864 /*
3865 Create pixel cache on disk.
3866 */
3867 status=AcquireMagickResource(DiskResource,cache_info->length);
3868 if (status == MagickFalse)
3869 {
3870 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003871 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003872 return(MagickFalse);
3873 }
cristy413f1302012-01-01 17:48:27 +00003874 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3875 {
3876 (void) ClosePixelCacheOnDisk(cache_info);
3877 *cache_info->cache_filename='\0';
3878 }
cristy3ed852e2009-09-05 21:47:34 +00003879 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3880 {
3881 RelinquishMagickResource(DiskResource,cache_info->length);
3882 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3883 image->filename);
3884 return(MagickFalse);
3885 }
3886 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3887 cache_info->length);
3888 if (status == MagickFalse)
3889 {
3890 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3891 image->filename);
3892 return(MagickFalse);
3893 }
cristyed231572011-07-14 02:18:59 +00003894 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003895 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003896 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003897 cache_info->type=DiskCache;
3898 else
3899 {
3900 status=AcquireMagickResource(MapResource,cache_info->length);
3901 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3902 (cache_info->type != MemoryCache))
3903 cache_info->type=DiskCache;
3904 else
3905 {
cristy4c08aed2011-07-01 19:47:50 +00003906 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003907 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003908 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003909 {
cristy3ed852e2009-09-05 21:47:34 +00003910 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003911 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003912 }
3913 else
3914 {
3915 /*
3916 Create file-backed memory-mapped pixel cache.
3917 */
cristy4c08aed2011-07-01 19:47:50 +00003918 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003919 (void) ClosePixelCacheOnDisk(cache_info);
3920 cache_info->type=MapCache;
3921 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003922 cache_info->metacontent=(void *) NULL;
3923 if (cache_info->metacontent_extent != 0)
3924 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003925 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003926 if ((source_info.storage_class != UndefinedClass) &&
3927 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003928 {
3929 status=ClonePixelCachePixels(cache_info,&source_info,
3930 exception);
3931 RelinquishPixelCachePixels(&source_info);
3932 }
3933 if (image->debug != MagickFalse)
3934 {
cristy413f1302012-01-01 17:48:27 +00003935 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003936 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003937 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003938 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003939 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003940 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003941 format);
cristy3ed852e2009-09-05 21:47:34 +00003942 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3943 message);
3944 }
cristy4c08aed2011-07-01 19:47:50 +00003945 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003946 }
3947 }
3948 RelinquishMagickResource(MapResource,cache_info->length);
3949 }
cristy4c08aed2011-07-01 19:47:50 +00003950 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003951 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003952 {
3953 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3954 RelinquishPixelCachePixels(&source_info);
3955 }
3956 if (image->debug != MagickFalse)
3957 {
cristyb9080c92009-12-01 20:13:26 +00003958 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003959 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003960 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003961 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003962 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003963 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003964 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3965 }
cristy4c08aed2011-07-01 19:47:50 +00003966 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003967}
3968
3969/*
3970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3971% %
3972% %
3973% %
3974+ P e r s i s t P i x e l C a c h e %
3975% %
3976% %
3977% %
3978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3979%
3980% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3981% persistent pixel cache is one that resides on disk and is not destroyed
3982% when the program exits.
3983%
3984% The format of the PersistPixelCache() method is:
3985%
3986% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3987% const MagickBooleanType attach,MagickOffsetType *offset,
3988% ExceptionInfo *exception)
3989%
3990% A description of each parameter follows:
3991%
3992% o image: the image.
3993%
3994% o filename: the persistent pixel cache filename.
3995%
cristyf3a6a9d2010-11-07 21:02:56 +00003996% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003997%
cristy3ed852e2009-09-05 21:47:34 +00003998% o initialize: A value other than zero initializes the persistent pixel
3999% cache.
4000%
4001% o offset: the offset in the persistent cache to store pixels.
4002%
4003% o exception: return any errors or warnings in this structure.
4004%
4005*/
4006MagickExport MagickBooleanType PersistPixelCache(Image *image,
4007 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4008 ExceptionInfo *exception)
4009{
4010 CacheInfo
4011 *cache_info,
4012 *clone_info;
4013
4014 Image
4015 clone_image;
4016
cristy3ed852e2009-09-05 21:47:34 +00004017 MagickBooleanType
4018 status;
4019
cristye076a6e2010-08-15 19:59:43 +00004020 ssize_t
4021 page_size;
4022
cristy3ed852e2009-09-05 21:47:34 +00004023 assert(image != (Image *) NULL);
4024 assert(image->signature == MagickSignature);
4025 if (image->debug != MagickFalse)
4026 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4027 assert(image->cache != (void *) NULL);
4028 assert(filename != (const char *) NULL);
4029 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004030 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004031 cache_info=(CacheInfo *) image->cache;
4032 assert(cache_info->signature == MagickSignature);
4033 if (attach != MagickFalse)
4034 {
4035 /*
cristy01b7eb02009-09-10 23:10:14 +00004036 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004037 */
4038 if (image->debug != MagickFalse)
4039 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004040 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004041 (void) CopyMagickString(cache_info->cache_filename,filename,
4042 MaxTextExtent);
4043 cache_info->type=DiskCache;
4044 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004045 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004046 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004047 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004048 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004049 }
cristy01b7eb02009-09-10 23:10:14 +00004050 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4051 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004052 {
cristyf84a1932010-01-03 18:00:18 +00004053 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004054 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004055 (cache_info->reference_count == 1))
4056 {
4057 int
4058 status;
4059
4060 /*
cristy01b7eb02009-09-10 23:10:14 +00004061 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004062 */
cristy320684d2011-09-23 14:55:47 +00004063 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004064 if (status == 0)
4065 {
4066 (void) CopyMagickString(cache_info->cache_filename,filename,
4067 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004068 *offset+=cache_info->length+page_size-(cache_info->length %
4069 page_size);
cristyf84a1932010-01-03 18:00:18 +00004070 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004071 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004072 if (image->debug != MagickFalse)
4073 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4074 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004075 return(MagickTrue);
4076 }
4077 }
cristyf84a1932010-01-03 18:00:18 +00004078 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004079 }
4080 /*
cristy01b7eb02009-09-10 23:10:14 +00004081 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004082 */
4083 clone_image=(*image);
4084 clone_info=(CacheInfo *) clone_image.cache;
4085 image->cache=ClonePixelCache(cache_info);
4086 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4087 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4088 cache_info->type=DiskCache;
4089 cache_info->offset=(*offset);
4090 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004091 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004092 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004093 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004094 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004095 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4096 return(status);
4097}
4098
4099/*
4100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4101% %
4102% %
4103% %
cristyc11dace2012-01-24 16:39:46 +00004104+ 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 +00004105% %
4106% %
4107% %
4108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4109%
cristyc11dace2012-01-24 16:39:46 +00004110% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4111% defined by the region rectangle and returns a pointer to the region. This
4112% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004113% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4114% pixels are transferred, otherwise a NULL is returned.
4115%
cristyc11dace2012-01-24 16:39:46 +00004116% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004117%
cristyc11dace2012-01-24 16:39:46 +00004118% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004119% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004120% const MagickBooleanType clone,NexusInfo *nexus_info,
4121% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004122%
4123% A description of each parameter follows:
4124%
4125% o image: the image.
4126%
4127% o x,y,columns,rows: These values define the perimeter of a region of
4128% pixels.
4129%
4130% o nexus_info: the cache nexus to set.
4131%
cristy65dbf172011-10-06 17:32:04 +00004132% o clone: clone the pixel cache.
4133%
cristy3ed852e2009-09-05 21:47:34 +00004134% o exception: return any errors or warnings in this structure.
4135%
4136*/
cristyc11dace2012-01-24 16:39:46 +00004137MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4138 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004139 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004140{
4141 CacheInfo
4142 *cache_info;
4143
4144 MagickOffsetType
4145 offset;
4146
4147 MagickSizeType
4148 number_pixels;
4149
4150 RectangleInfo
4151 region;
4152
4153 /*
4154 Validate pixel cache geometry.
4155 */
cristye7cc7cf2010-09-21 13:26:47 +00004156 assert(image != (const Image *) NULL);
4157 assert(image->signature == MagickSignature);
4158 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004159 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004160 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004161 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004162 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004163 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4164 {
4165 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004166 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004167 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004168 }
cristybb503372010-05-27 20:51:26 +00004169 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4170 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004171 {
4172 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004173 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004174 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004175 }
4176 offset=(MagickOffsetType) y*cache_info->columns+x;
4177 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004178 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004179 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4180 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4181 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004182 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004183 /*
4184 Return pixel cache.
4185 */
4186 region.x=x;
4187 region.y=y;
4188 region.width=columns;
4189 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004190 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004191}
4192
4193/*
4194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4195% %
4196% %
4197% %
4198+ 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 %
4199% %
4200% %
4201% %
4202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4203%
4204% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4205% defined by the region rectangle and returns a pointer to the region. This
4206% region is subsequently transferred from the pixel cache with
4207% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4208% pixels are transferred, otherwise a NULL is returned.
4209%
4210% The format of the QueueAuthenticPixelsCache() method is:
4211%
cristy4c08aed2011-07-01 19:47:50 +00004212% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004213% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004214% ExceptionInfo *exception)
4215%
4216% A description of each parameter follows:
4217%
4218% o image: the image.
4219%
4220% o x,y,columns,rows: These values define the perimeter of a region of
4221% pixels.
4222%
4223% o exception: return any errors or warnings in this structure.
4224%
4225*/
cristy4c08aed2011-07-01 19:47:50 +00004226static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004227 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004228 ExceptionInfo *exception)
4229{
4230 CacheInfo
4231 *cache_info;
4232
cristy5c9e6f22010-09-17 17:31:01 +00004233 const int
4234 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004235
cristy4c08aed2011-07-01 19:47:50 +00004236 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004237 *q;
cristy4c08aed2011-07-01 19:47:50 +00004238
cristye7cc7cf2010-09-21 13:26:47 +00004239 assert(image != (const Image *) NULL);
4240 assert(image->signature == MagickSignature);
4241 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004242 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004243 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004244 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004245 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004246 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004247 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004248}
4249
4250/*
4251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4252% %
4253% %
4254% %
4255% Q u e u e A u t h e n t i c P i x e l s %
4256% %
4257% %
4258% %
4259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4260%
4261% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004262% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004263% region is returned, otherwise NULL is returned. The returned pointer may
4264% point to a temporary working buffer for the pixels or it may point to the
4265% final location of the pixels in memory.
4266%
4267% Write-only access means that any existing pixel values corresponding to
4268% the region are ignored. This is useful if the initial image is being
4269% created from scratch, or if the existing pixel values are to be
4270% completely replaced without need to refer to their pre-existing values.
4271% The application is free to read and write the pixel buffer returned by
4272% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4273% initialize the pixel array values. Initializing pixel array values is the
4274% application's responsibility.
4275%
4276% Performance is maximized if the selected region is part of one row, or
4277% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004278% pixels in-place (without a copy) if the image is in memory, or in a
4279% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004280% by the user.
4281%
4282% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004283% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4284% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4285% obtain the meta-content (of type void) corresponding to the region.
4286% Once the Quantum (and/or Quantum) array has been updated, the
4287% changes must be saved back to the underlying image using
4288% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004289%
4290% The format of the QueueAuthenticPixels() method is:
4291%
cristy4c08aed2011-07-01 19:47:50 +00004292% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004293% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004294% ExceptionInfo *exception)
4295%
4296% A description of each parameter follows:
4297%
4298% o image: the image.
4299%
4300% o x,y,columns,rows: These values define the perimeter of a region of
4301% pixels.
4302%
4303% o exception: return any errors or warnings in this structure.
4304%
4305*/
cristy4c08aed2011-07-01 19:47:50 +00004306MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004307 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004308 ExceptionInfo *exception)
4309{
4310 CacheInfo
4311 *cache_info;
4312
cristy2036f5c2010-09-19 21:18:17 +00004313 const int
4314 id = GetOpenMPThreadId();
4315
cristy4c08aed2011-07-01 19:47:50 +00004316 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004317 *q;
cristy4c08aed2011-07-01 19:47:50 +00004318
cristy3ed852e2009-09-05 21:47:34 +00004319 assert(image != (Image *) NULL);
4320 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004321 assert(image->cache != (Cache) NULL);
4322 cache_info=(CacheInfo *) image->cache;
4323 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004324 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004325 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004326 {
cristyc36c8822012-02-14 14:02:36 +00004327 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4328 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004329 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004330 }
cristy2036f5c2010-09-19 21:18:17 +00004331 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004332 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004333 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004334 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004335}
4336
4337/*
4338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4339% %
4340% %
4341% %
cristy4c08aed2011-07-01 19:47:50 +00004342+ 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 +00004343% %
4344% %
4345% %
4346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4347%
cristy4c08aed2011-07-01 19:47:50 +00004348% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004349% the pixel cache.
4350%
cristy4c08aed2011-07-01 19:47:50 +00004351% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004352%
cristy4c08aed2011-07-01 19:47:50 +00004353% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004354% NexusInfo *nexus_info,ExceptionInfo *exception)
4355%
4356% A description of each parameter follows:
4357%
4358% o cache_info: the pixel cache.
4359%
cristy4c08aed2011-07-01 19:47:50 +00004360% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004361%
4362% o exception: return any errors or warnings in this structure.
4363%
4364*/
cristy4c08aed2011-07-01 19:47:50 +00004365static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004366 NexusInfo *nexus_info,ExceptionInfo *exception)
4367{
4368 MagickOffsetType
4369 count,
4370 offset;
4371
4372 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004373 extent,
4374 length;
cristy3ed852e2009-09-05 21:47:34 +00004375
cristybb503372010-05-27 20:51:26 +00004376 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004377 y;
4378
cristy4c08aed2011-07-01 19:47:50 +00004379 register unsigned char
4380 *restrict q;
4381
cristybb503372010-05-27 20:51:26 +00004382 size_t
cristy3ed852e2009-09-05 21:47:34 +00004383 rows;
4384
cristy4c08aed2011-07-01 19:47:50 +00004385 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004386 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004387 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004388 return(MagickTrue);
4389 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4390 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004391 length=(MagickSizeType) nexus_info->region.width*
4392 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004393 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004394 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004395 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004396 switch (cache_info->type)
4397 {
4398 case MemoryCache:
4399 case MapCache:
4400 {
cristy4c08aed2011-07-01 19:47:50 +00004401 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004402 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004403
4404 /*
cristy4c08aed2011-07-01 19:47:50 +00004405 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004406 */
cristydd341db2010-03-04 19:06:38 +00004407 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004408 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004409 {
cristy48078b12010-09-23 17:11:01 +00004410 length=extent;
cristydd341db2010-03-04 19:06:38 +00004411 rows=1UL;
4412 }
cristy4c08aed2011-07-01 19:47:50 +00004413 p=(unsigned char *) cache_info->metacontent+offset*
4414 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004415 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004416 {
cristy8f036fe2010-09-18 02:02:00 +00004417 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004418 p+=cache_info->metacontent_extent*cache_info->columns;
4419 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004420 }
4421 break;
4422 }
4423 case DiskCache:
4424 {
4425 /*
cristy4c08aed2011-07-01 19:47:50 +00004426 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004427 */
4428 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4429 {
4430 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4431 cache_info->cache_filename);
4432 return(MagickFalse);
4433 }
cristydd341db2010-03-04 19:06:38 +00004434 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004435 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004436 {
cristy48078b12010-09-23 17:11:01 +00004437 length=extent;
cristydd341db2010-03-04 19:06:38 +00004438 rows=1UL;
4439 }
cristy48078b12010-09-23 17:11:01 +00004440 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004441 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004442 {
cristy48078b12010-09-23 17:11:01 +00004443 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004444 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004445 cache_info->metacontent_extent,length,(unsigned char *) q);
4446 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004447 break;
4448 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004449 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004450 }
cristyc11dace2012-01-24 16:39:46 +00004451 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4452 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004453 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004454 {
4455 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4456 cache_info->cache_filename);
4457 return(MagickFalse);
4458 }
4459 break;
4460 }
4461 default:
4462 break;
4463 }
4464 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004465 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004466 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004467 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004468 nexus_info->region.width,(double) nexus_info->region.height,(double)
4469 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004470 return(MagickTrue);
4471}
4472
4473/*
4474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4475% %
4476% %
4477% %
4478+ R e a d P i x e l C a c h e P i x e l s %
4479% %
4480% %
4481% %
4482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4483%
4484% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4485% cache.
4486%
4487% The format of the ReadPixelCachePixels() method is:
4488%
4489% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4490% NexusInfo *nexus_info,ExceptionInfo *exception)
4491%
4492% A description of each parameter follows:
4493%
4494% o cache_info: the pixel cache.
4495%
4496% o nexus_info: the cache nexus to read the pixels.
4497%
4498% o exception: return any errors or warnings in this structure.
4499%
4500*/
4501static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4502 NexusInfo *nexus_info,ExceptionInfo *exception)
4503{
4504 MagickOffsetType
4505 count,
4506 offset;
4507
4508 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004509 extent,
4510 length;
cristy3ed852e2009-09-05 21:47:34 +00004511
cristy4c08aed2011-07-01 19:47:50 +00004512 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004513 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004514
cristye076a6e2010-08-15 19:59:43 +00004515 register ssize_t
4516 y;
4517
cristybb503372010-05-27 20:51:26 +00004518 size_t
cristy3ed852e2009-09-05 21:47:34 +00004519 rows;
4520
cristy4c08aed2011-07-01 19:47:50 +00004521 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004522 return(MagickTrue);
4523 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4524 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004525 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004526 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004527 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004528 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004529 q=nexus_info->pixels;
4530 switch (cache_info->type)
4531 {
4532 case MemoryCache:
4533 case MapCache:
4534 {
cristy4c08aed2011-07-01 19:47:50 +00004535 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004536 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004537
4538 /*
4539 Read pixels from memory.
4540 */
cristydd341db2010-03-04 19:06:38 +00004541 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004542 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004543 {
cristy48078b12010-09-23 17:11:01 +00004544 length=extent;
cristydd341db2010-03-04 19:06:38 +00004545 rows=1UL;
4546 }
cristyed231572011-07-14 02:18:59 +00004547 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004548 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004549 {
cristy8f036fe2010-09-18 02:02:00 +00004550 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004551 p+=cache_info->number_channels*cache_info->columns;
4552 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004553 }
4554 break;
4555 }
4556 case DiskCache:
4557 {
4558 /*
4559 Read pixels from disk.
4560 */
4561 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4562 {
4563 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4564 cache_info->cache_filename);
4565 return(MagickFalse);
4566 }
cristydd341db2010-03-04 19:06:38 +00004567 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004568 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004569 {
cristy48078b12010-09-23 17:11:01 +00004570 length=extent;
cristydd341db2010-03-04 19:06:38 +00004571 rows=1UL;
4572 }
cristybb503372010-05-27 20:51:26 +00004573 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004574 {
4575 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004576 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004577 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004578 break;
4579 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004580 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004581 }
cristyc11dace2012-01-24 16:39:46 +00004582 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4583 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004584 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004585 {
4586 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4587 cache_info->cache_filename);
4588 return(MagickFalse);
4589 }
4590 break;
4591 }
4592 default:
4593 break;
4594 }
4595 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004596 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004597 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004598 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004599 nexus_info->region.width,(double) nexus_info->region.height,(double)
4600 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004601 return(MagickTrue);
4602}
4603
4604/*
4605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4606% %
4607% %
4608% %
4609+ R e f e r e n c e P i x e l C a c h e %
4610% %
4611% %
4612% %
4613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4614%
4615% ReferencePixelCache() increments the reference count associated with the
4616% pixel cache returning a pointer to the cache.
4617%
4618% The format of the ReferencePixelCache method is:
4619%
4620% Cache ReferencePixelCache(Cache cache_info)
4621%
4622% A description of each parameter follows:
4623%
4624% o cache_info: the pixel cache.
4625%
4626*/
cristya6577ff2011-09-02 19:54:26 +00004627MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004628{
4629 CacheInfo
4630 *cache_info;
4631
4632 assert(cache != (Cache *) NULL);
4633 cache_info=(CacheInfo *) cache;
4634 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004635 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004636 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004637 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004638 return(cache_info);
4639}
4640
4641/*
4642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4643% %
4644% %
4645% %
4646+ S e t P i x e l C a c h e M e t h o d s %
4647% %
4648% %
4649% %
4650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4651%
4652% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4653%
4654% The format of the SetPixelCacheMethods() method is:
4655%
4656% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4657%
4658% A description of each parameter follows:
4659%
4660% o cache: the pixel cache.
4661%
4662% o cache_methods: Specifies a pointer to a CacheMethods structure.
4663%
4664*/
cristya6577ff2011-09-02 19:54:26 +00004665MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004666{
4667 CacheInfo
4668 *cache_info;
4669
4670 GetOneAuthenticPixelFromHandler
4671 get_one_authentic_pixel_from_handler;
4672
4673 GetOneVirtualPixelFromHandler
4674 get_one_virtual_pixel_from_handler;
4675
4676 /*
4677 Set cache pixel methods.
4678 */
4679 assert(cache != (Cache) NULL);
4680 assert(cache_methods != (CacheMethods *) NULL);
4681 cache_info=(CacheInfo *) cache;
4682 assert(cache_info->signature == MagickSignature);
4683 if (cache_info->debug != MagickFalse)
4684 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4685 cache_info->filename);
4686 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4687 cache_info->methods.get_virtual_pixel_handler=
4688 cache_methods->get_virtual_pixel_handler;
4689 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4690 cache_info->methods.destroy_pixel_handler=
4691 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004692 if (cache_methods->get_virtual_metacontent_from_handler !=
4693 (GetVirtualMetacontentFromHandler) NULL)
4694 cache_info->methods.get_virtual_metacontent_from_handler=
4695 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004696 if (cache_methods->get_authentic_pixels_handler !=
4697 (GetAuthenticPixelsHandler) NULL)
4698 cache_info->methods.get_authentic_pixels_handler=
4699 cache_methods->get_authentic_pixels_handler;
4700 if (cache_methods->queue_authentic_pixels_handler !=
4701 (QueueAuthenticPixelsHandler) NULL)
4702 cache_info->methods.queue_authentic_pixels_handler=
4703 cache_methods->queue_authentic_pixels_handler;
4704 if (cache_methods->sync_authentic_pixels_handler !=
4705 (SyncAuthenticPixelsHandler) NULL)
4706 cache_info->methods.sync_authentic_pixels_handler=
4707 cache_methods->sync_authentic_pixels_handler;
4708 if (cache_methods->get_authentic_pixels_from_handler !=
4709 (GetAuthenticPixelsFromHandler) NULL)
4710 cache_info->methods.get_authentic_pixels_from_handler=
4711 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004712 if (cache_methods->get_authentic_metacontent_from_handler !=
4713 (GetAuthenticMetacontentFromHandler) NULL)
4714 cache_info->methods.get_authentic_metacontent_from_handler=
4715 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004716 get_one_virtual_pixel_from_handler=
4717 cache_info->methods.get_one_virtual_pixel_from_handler;
4718 if (get_one_virtual_pixel_from_handler !=
4719 (GetOneVirtualPixelFromHandler) NULL)
4720 cache_info->methods.get_one_virtual_pixel_from_handler=
4721 cache_methods->get_one_virtual_pixel_from_handler;
4722 get_one_authentic_pixel_from_handler=
4723 cache_methods->get_one_authentic_pixel_from_handler;
4724 if (get_one_authentic_pixel_from_handler !=
4725 (GetOneAuthenticPixelFromHandler) NULL)
4726 cache_info->methods.get_one_authentic_pixel_from_handler=
4727 cache_methods->get_one_authentic_pixel_from_handler;
4728}
4729
4730/*
4731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4732% %
4733% %
4734% %
4735+ S e t P i x e l C a c h e N e x u s P i x e l s %
4736% %
4737% %
4738% %
4739%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4740%
4741% SetPixelCacheNexusPixels() defines the region of the cache for the
4742% specified cache nexus.
4743%
4744% The format of the SetPixelCacheNexusPixels() method is:
4745%
cristy265a2b22012-05-11 12:48:50 +00004746% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004747% const RectangleInfo *region,NexusInfo *nexus_info,
4748% ExceptionInfo *exception)
4749%
4750% A description of each parameter follows:
4751%
4752% o image: the image.
4753%
cristy265a2b22012-05-11 12:48:50 +00004754% o mode: ReadMode, WriteMode, or IOMode.
4755%
cristy3ed852e2009-09-05 21:47:34 +00004756% o region: A pointer to the RectangleInfo structure that defines the
4757% region of this particular cache nexus.
4758%
4759% o nexus_info: the cache nexus to set.
4760%
4761% o exception: return any errors or warnings in this structure.
4762%
4763*/
cristyabd6e372010-09-15 19:11:26 +00004764
cristyf1832792012-05-08 18:38:18 +00004765static inline MagickBooleanType AcquireCacheNexusPixels(
4766 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4767 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004768{
4769 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4770 return(MagickFalse);
4771 nexus_info->mapped=MagickFalse;
cristy64c3edf2012-04-13 18:50:13 +00004772 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00004773 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004774 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004775 {
4776 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004777 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004778 nexus_info->length);
4779 }
cristy4c08aed2011-07-01 19:47:50 +00004780 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004781 {
4782 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004783 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004784 cache_info->filename);
4785 return(MagickFalse);
4786 }
4787 return(MagickTrue);
4788}
4789
cristyadf82722012-05-11 17:34:16 +00004790static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4791 const MapMode mode)
4792{
cristyfc5845e2012-05-11 18:18:13 +00004793 if (mode == ReadMode)
4794 {
4795 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4796 return;
4797 }
4798 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004799}
4800
cristy265a2b22012-05-11 12:48:50 +00004801static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004802 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4803{
4804 CacheInfo
4805 *cache_info;
4806
4807 MagickBooleanType
4808 status;
4809
cristy3ed852e2009-09-05 21:47:34 +00004810 MagickSizeType
4811 length,
4812 number_pixels;
4813
cristy3ed852e2009-09-05 21:47:34 +00004814 cache_info=(CacheInfo *) image->cache;
4815 assert(cache_info->signature == MagickSignature);
4816 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004817 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004818 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004819 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004820 {
cristybb503372010-05-27 20:51:26 +00004821 ssize_t
cristybad067a2010-02-15 17:20:55 +00004822 x,
4823 y;
cristy3ed852e2009-09-05 21:47:34 +00004824
cristyeaedf062010-05-29 22:36:02 +00004825 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4826 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004827 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4828 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004829 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004830 ((nexus_info->region.width == cache_info->columns) ||
4831 ((nexus_info->region.width % cache_info->columns) == 0)))))
4832 {
4833 MagickOffsetType
4834 offset;
4835
4836 /*
4837 Pixels are accessed directly from memory.
4838 */
4839 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4840 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004841 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004842 offset;
4843 nexus_info->metacontent=(void *) NULL;
4844 if (cache_info->metacontent_extent != 0)
4845 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4846 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004847 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004848 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004849 }
4850 }
4851 /*
4852 Pixels are stored in a cache region until they are synced to the cache.
4853 */
4854 number_pixels=(MagickSizeType) nexus_info->region.width*
4855 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004856 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004857 if (cache_info->metacontent_extent != 0)
4858 length+=number_pixels*cache_info->metacontent_extent;
4859 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004860 {
4861 nexus_info->length=length;
4862 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4863 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004864 {
4865 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004866 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004867 }
cristy3ed852e2009-09-05 21:47:34 +00004868 }
4869 else
4870 if (nexus_info->length != length)
4871 {
4872 RelinquishCacheNexusPixels(nexus_info);
4873 nexus_info->length=length;
4874 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4875 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004876 {
4877 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004878 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004879 }
cristy3ed852e2009-09-05 21:47:34 +00004880 }
4881 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004882 nexus_info->metacontent=(void *) NULL;
4883 if (cache_info->metacontent_extent != 0)
4884 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004885 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004886 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004887 return(nexus_info->pixels);
4888}
4889
4890/*
4891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4892% %
4893% %
4894% %
4895% 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 %
4896% %
4897% %
4898% %
4899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4900%
4901% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4902% pixel cache and returns the previous setting. A virtual pixel is any pixel
4903% access that is outside the boundaries of the image cache.
4904%
4905% The format of the SetPixelCacheVirtualMethod() method is:
4906%
cristy387430f2012-02-07 13:09:46 +00004907% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4908% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004909%
4910% A description of each parameter follows:
4911%
4912% o image: the image.
4913%
4914% o virtual_pixel_method: choose the type of virtual pixel.
4915%
cristy387430f2012-02-07 13:09:46 +00004916% o exception: return any errors or warnings in this structure.
4917%
cristy3ed852e2009-09-05 21:47:34 +00004918*/
cristy3d4cb882012-02-07 19:11:26 +00004919
4920static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4921 ExceptionInfo *exception)
4922{
4923 CacheInfo
4924 *cache_info;
4925
cristyf2719112012-05-06 18:38:46 +00004926 CacheView
4927 *image_view;
4928
cristy3d4cb882012-02-07 19:11:26 +00004929 MagickBooleanType
4930 status;
4931
4932 ssize_t
4933 y;
4934
4935 assert(image != (Image *) NULL);
4936 assert(image->signature == MagickSignature);
4937 if (image->debug != MagickFalse)
4938 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4939 assert(image->cache != (Cache) NULL);
4940 cache_info=(CacheInfo *) image->cache;
4941 assert(cache_info->signature == MagickSignature);
4942 image->matte=MagickTrue;
4943 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004944 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004945#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00004946 #pragma omp parallel for schedule(static) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00004947 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004948#endif
4949 for (y=0; y < (ssize_t) image->rows; y++)
4950 {
cristy3d4cb882012-02-07 19:11:26 +00004951 register Quantum
4952 *restrict q;
4953
4954 register ssize_t
4955 x;
4956
4957 if (status == MagickFalse)
4958 continue;
cristy23d198a2012-03-13 13:48:08 +00004959 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004960 if (q == (Quantum *) NULL)
4961 {
4962 status=MagickFalse;
4963 continue;
4964 }
4965 for (x=0; x < (ssize_t) image->columns; x++)
4966 {
4967 SetPixelAlpha(image,alpha,q);
4968 q+=GetPixelChannels(image);
4969 }
cristy23d198a2012-03-13 13:48:08 +00004970 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004971 }
cristy23d198a2012-03-13 13:48:08 +00004972 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004973 return(status);
4974}
4975
cristy387430f2012-02-07 13:09:46 +00004976MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4977 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004978{
4979 CacheInfo
4980 *cache_info;
4981
4982 VirtualPixelMethod
4983 method;
4984
4985 assert(image != (Image *) NULL);
4986 assert(image->signature == MagickSignature);
4987 if (image->debug != MagickFalse)
4988 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4989 assert(image->cache != (Cache) NULL);
4990 cache_info=(CacheInfo *) image->cache;
4991 assert(cache_info->signature == MagickSignature);
4992 method=cache_info->virtual_pixel_method;
4993 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004994 switch (virtual_pixel_method)
4995 {
4996 case BackgroundVirtualPixelMethod:
4997 {
4998 if ((image->background_color.matte != MagickFalse) &&
4999 (image->matte == MagickFalse))
cristy3d4cb882012-02-07 19:11:26 +00005000 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00005001 break;
5002 }
5003 case TransparentVirtualPixelMethod:
5004 {
5005 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00005006 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00005007 break;
5008 }
5009 default:
5010 break;
5011 }
cristy3ed852e2009-09-05 21:47:34 +00005012 return(method);
5013}
5014
5015/*
5016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5017% %
5018% %
5019% %
5020+ 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 %
5021% %
5022% %
5023% %
5024%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5025%
5026% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5027% in-memory or disk cache. The method returns MagickTrue if the pixel region
5028% is synced, otherwise MagickFalse.
5029%
5030% The format of the SyncAuthenticPixelCacheNexus() method is:
5031%
5032% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5033% NexusInfo *nexus_info,ExceptionInfo *exception)
5034%
5035% A description of each parameter follows:
5036%
5037% o image: the image.
5038%
5039% o nexus_info: the cache nexus to sync.
5040%
5041% o exception: return any errors or warnings in this structure.
5042%
5043*/
cristya6577ff2011-09-02 19:54:26 +00005044MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005045 NexusInfo *nexus_info,ExceptionInfo *exception)
5046{
5047 CacheInfo
5048 *cache_info;
5049
5050 MagickBooleanType
5051 status;
5052
5053 /*
5054 Transfer pixels to the cache.
5055 */
5056 assert(image != (Image *) NULL);
5057 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005058 if (image->cache == (Cache) NULL)
5059 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5060 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005061 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005062 if (cache_info->type == UndefinedCache)
5063 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005064 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005065 return(MagickTrue);
5066 assert(cache_info->signature == MagickSignature);
5067 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005068 if ((cache_info->metacontent_extent != 0) &&
5069 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005070 return(MagickFalse);
5071 return(status);
5072}
5073
5074/*
5075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5076% %
5077% %
5078% %
5079+ S y n c A u t h e n t i c P i x e l C a c h e %
5080% %
5081% %
5082% %
5083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5084%
5085% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5086% or disk cache. The method returns MagickTrue if the pixel region is synced,
5087% otherwise MagickFalse.
5088%
5089% The format of the SyncAuthenticPixelsCache() method is:
5090%
5091% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5092% ExceptionInfo *exception)
5093%
5094% A description of each parameter follows:
5095%
5096% o image: the image.
5097%
5098% o exception: return any errors or warnings in this structure.
5099%
5100*/
5101static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5102 ExceptionInfo *exception)
5103{
5104 CacheInfo
5105 *cache_info;
5106
cristy5c9e6f22010-09-17 17:31:01 +00005107 const int
5108 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005109
cristy4c08aed2011-07-01 19:47:50 +00005110 MagickBooleanType
5111 status;
5112
cristye7cc7cf2010-09-21 13:26:47 +00005113 assert(image != (Image *) NULL);
5114 assert(image->signature == MagickSignature);
5115 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005116 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005117 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005118 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005119 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5120 exception);
5121 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005122}
5123
5124/*
5125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5126% %
5127% %
5128% %
5129% S y n c A u t h e n t i c P i x e l s %
5130% %
5131% %
5132% %
5133%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5134%
5135% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5136% The method returns MagickTrue if the pixel region is flushed, otherwise
5137% MagickFalse.
5138%
5139% The format of the SyncAuthenticPixels() method is:
5140%
5141% MagickBooleanType SyncAuthenticPixels(Image *image,
5142% ExceptionInfo *exception)
5143%
5144% A description of each parameter follows:
5145%
5146% o image: the image.
5147%
5148% o exception: return any errors or warnings in this structure.
5149%
5150*/
5151MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5152 ExceptionInfo *exception)
5153{
5154 CacheInfo
5155 *cache_info;
5156
cristy2036f5c2010-09-19 21:18:17 +00005157 const int
5158 id = GetOpenMPThreadId();
5159
cristy4c08aed2011-07-01 19:47:50 +00005160 MagickBooleanType
5161 status;
5162
cristy3ed852e2009-09-05 21:47:34 +00005163 assert(image != (Image *) NULL);
5164 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005165 assert(image->cache != (Cache) NULL);
5166 cache_info=(CacheInfo *) image->cache;
5167 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005168 if (cache_info->methods.sync_authentic_pixels_handler !=
5169 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005170 {
5171 status=cache_info->methods.sync_authentic_pixels_handler(image,
5172 exception);
5173 return(status);
5174 }
cristy2036f5c2010-09-19 21:18:17 +00005175 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005176 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5177 exception);
5178 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005179}
5180
5181/*
5182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5183% %
5184% %
5185% %
cristyd1dd6e42011-09-04 01:46:08 +00005186+ 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 +00005187% %
5188% %
5189% %
5190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5191%
5192% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5193% The method returns MagickTrue if the pixel region is flushed, otherwise
5194% MagickFalse.
5195%
5196% The format of the SyncImagePixelCache() method is:
5197%
5198% MagickBooleanType SyncImagePixelCache(Image *image,
5199% ExceptionInfo *exception)
5200%
5201% A description of each parameter follows:
5202%
5203% o image: the image.
5204%
5205% o exception: return any errors or warnings in this structure.
5206%
5207*/
cristyd1dd6e42011-09-04 01:46:08 +00005208MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005209 ExceptionInfo *exception)
5210{
5211 CacheInfo
5212 *cache_info;
5213
5214 assert(image != (Image *) NULL);
5215 assert(exception != (ExceptionInfo *) NULL);
5216 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5217 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5218}
5219
5220/*
5221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222% %
5223% %
5224% %
cristy4c08aed2011-07-01 19:47:50 +00005225+ 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 +00005226% %
5227% %
5228% %
5229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5230%
cristy4c08aed2011-07-01 19:47:50 +00005231% WritePixelCacheMetacontent() writes the meta-content to the specified region
5232% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005233%
cristy4c08aed2011-07-01 19:47:50 +00005234% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005235%
cristy4c08aed2011-07-01 19:47:50 +00005236% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005237% NexusInfo *nexus_info,ExceptionInfo *exception)
5238%
5239% A description of each parameter follows:
5240%
5241% o cache_info: the pixel cache.
5242%
cristy4c08aed2011-07-01 19:47:50 +00005243% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005244%
5245% o exception: return any errors or warnings in this structure.
5246%
5247*/
cristy4c08aed2011-07-01 19:47:50 +00005248static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005249 NexusInfo *nexus_info,ExceptionInfo *exception)
5250{
5251 MagickOffsetType
5252 count,
5253 offset;
5254
5255 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005256 extent,
5257 length;
cristy3ed852e2009-09-05 21:47:34 +00005258
cristy4c08aed2011-07-01 19:47:50 +00005259 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005260 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005261
cristybb503372010-05-27 20:51:26 +00005262 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005263 y;
5264
cristybb503372010-05-27 20:51:26 +00005265 size_t
cristy3ed852e2009-09-05 21:47:34 +00005266 rows;
5267
cristy4c08aed2011-07-01 19:47:50 +00005268 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005269 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005270 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005271 return(MagickTrue);
5272 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5273 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005274 length=(MagickSizeType) nexus_info->region.width*
5275 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005276 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005277 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005278 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005279 switch (cache_info->type)
5280 {
5281 case MemoryCache:
5282 case MapCache:
5283 {
cristy4c08aed2011-07-01 19:47:50 +00005284 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005285 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005286
5287 /*
cristy4c08aed2011-07-01 19:47:50 +00005288 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005289 */
cristydd341db2010-03-04 19:06:38 +00005290 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005291 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005292 {
cristy48078b12010-09-23 17:11:01 +00005293 length=extent;
cristydd341db2010-03-04 19:06:38 +00005294 rows=1UL;
5295 }
cristy4c08aed2011-07-01 19:47:50 +00005296 q=(unsigned char *) cache_info->metacontent+offset*
5297 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005298 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005299 {
cristy8f036fe2010-09-18 02:02:00 +00005300 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005301 p+=nexus_info->region.width*cache_info->metacontent_extent;
5302 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005303 }
5304 break;
5305 }
5306 case DiskCache:
5307 {
5308 /*
cristy4c08aed2011-07-01 19:47:50 +00005309 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005310 */
5311 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5312 {
5313 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5314 cache_info->cache_filename);
5315 return(MagickFalse);
5316 }
cristydd341db2010-03-04 19:06:38 +00005317 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005318 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005319 {
cristy48078b12010-09-23 17:11:01 +00005320 length=extent;
cristydd341db2010-03-04 19:06:38 +00005321 rows=1UL;
5322 }
cristy48078b12010-09-23 17:11:01 +00005323 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005324 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005325 {
cristy48078b12010-09-23 17:11:01 +00005326 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005327 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005328 cache_info->metacontent_extent,length,(const unsigned char *) p);
5329 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005330 break;
cristy4c08aed2011-07-01 19:47:50 +00005331 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005332 offset+=cache_info->columns;
5333 }
cristyc11dace2012-01-24 16:39:46 +00005334 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5335 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005336 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005337 {
5338 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5339 cache_info->cache_filename);
5340 return(MagickFalse);
5341 }
5342 break;
5343 }
5344 default:
5345 break;
5346 }
5347 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005348 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005349 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005350 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005351 nexus_info->region.width,(double) nexus_info->region.height,(double)
5352 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005353 return(MagickTrue);
5354}
5355
5356/*
5357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5358% %
5359% %
5360% %
5361+ W r i t e C a c h e P i x e l s %
5362% %
5363% %
5364% %
5365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5366%
5367% WritePixelCachePixels() writes image pixels to the specified region of the
5368% pixel cache.
5369%
5370% The format of the WritePixelCachePixels() method is:
5371%
5372% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5373% NexusInfo *nexus_info,ExceptionInfo *exception)
5374%
5375% A description of each parameter follows:
5376%
5377% o cache_info: the pixel cache.
5378%
5379% o nexus_info: the cache nexus to write the pixels.
5380%
5381% o exception: return any errors or warnings in this structure.
5382%
5383*/
5384static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5385 NexusInfo *nexus_info,ExceptionInfo *exception)
5386{
5387 MagickOffsetType
5388 count,
5389 offset;
5390
5391 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005392 extent,
5393 length;
cristy3ed852e2009-09-05 21:47:34 +00005394
cristy4c08aed2011-07-01 19:47:50 +00005395 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005396 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005397
cristybb503372010-05-27 20:51:26 +00005398 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005399 y;
5400
cristybb503372010-05-27 20:51:26 +00005401 size_t
cristy3ed852e2009-09-05 21:47:34 +00005402 rows;
5403
cristy4c08aed2011-07-01 19:47:50 +00005404 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005405 return(MagickTrue);
5406 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5407 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005408 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005409 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005410 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005411 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005412 p=nexus_info->pixels;
5413 switch (cache_info->type)
5414 {
5415 case MemoryCache:
5416 case MapCache:
5417 {
cristy4c08aed2011-07-01 19:47:50 +00005418 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005419 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005420
5421 /*
5422 Write pixels to memory.
5423 */
cristydd341db2010-03-04 19:06:38 +00005424 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005425 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005426 {
cristy48078b12010-09-23 17:11:01 +00005427 length=extent;
cristydd341db2010-03-04 19:06:38 +00005428 rows=1UL;
5429 }
cristyed231572011-07-14 02:18:59 +00005430 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005431 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005432 {
cristy8f036fe2010-09-18 02:02:00 +00005433 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005434 p+=nexus_info->region.width*cache_info->number_channels;
5435 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005436 }
5437 break;
5438 }
5439 case DiskCache:
5440 {
5441 /*
5442 Write pixels to disk.
5443 */
5444 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5445 {
5446 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5447 cache_info->cache_filename);
5448 return(MagickFalse);
5449 }
cristydd341db2010-03-04 19:06:38 +00005450 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005451 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005452 {
cristy48078b12010-09-23 17:11:01 +00005453 length=extent;
cristydd341db2010-03-04 19:06:38 +00005454 rows=1UL;
5455 }
cristybb503372010-05-27 20:51:26 +00005456 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005457 {
5458 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005459 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005460 p);
5461 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005462 break;
cristyed231572011-07-14 02:18:59 +00005463 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005464 offset+=cache_info->columns;
5465 }
cristyc11dace2012-01-24 16:39:46 +00005466 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5467 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005468 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005469 {
5470 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5471 cache_info->cache_filename);
5472 return(MagickFalse);
5473 }
5474 break;
5475 }
5476 default:
5477 break;
5478 }
5479 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005480 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005481 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005482 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005483 nexus_info->region.width,(double) nexus_info->region.height,(double)
5484 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005485 return(MagickTrue);
5486}