blob: a210b6547e1d2bcec740c59ca5bf50b39210953f [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"
cristy3d9f5ba2012-06-26 13:37:31 +000049#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000050#include "MagickCore/composite-private.h"
51#include "MagickCore/exception.h"
52#include "MagickCore/exception-private.h"
53#include "MagickCore/geometry.h"
54#include "MagickCore/list.h"
55#include "MagickCore/log.h"
56#include "MagickCore/magick.h"
57#include "MagickCore/memory_.h"
cristyadf82722012-05-11 17:34:16 +000058#include "MagickCore/memory-private.h"
cristyd2d11ec2012-03-28 13:53:49 +000059#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000060#include "MagickCore/pixel.h"
61#include "MagickCore/pixel-accessor.h"
62#include "MagickCore/policy.h"
63#include "MagickCore/quantum.h"
64#include "MagickCore/random_.h"
65#include "MagickCore/resource_.h"
66#include "MagickCore/semaphore.h"
67#include "MagickCore/splay-tree.h"
68#include "MagickCore/string_.h"
69#include "MagickCore/string-private.h"
70#include "MagickCore/thread-private.h"
71#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000072#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000073#if defined(MAGICKCORE_ZLIB_DELEGATE)
74#include "zlib.h"
75#endif
76
77/*
cristy30097232010-07-01 02:16:30 +000078 Define declarations.
79*/
80#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
cristyc11dace2012-01-24 16:39:46 +000081#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
82 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
cristy30097232010-07-01 02:16:30 +000083
84/*
cristy3ed852e2009-09-05 21:47:34 +000085 Typedef declarations.
86*/
87typedef struct _MagickModulo
88{
cristybb503372010-05-27 20:51:26 +000089 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000090 quotient,
91 remainder;
92} MagickModulo;
93
94struct _NexusInfo
95{
96 MagickBooleanType
97 mapped;
98
99 RectangleInfo
100 region;
101
102 MagickSizeType
103 length;
104
cristy4c08aed2011-07-01 19:47:50 +0000105 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000106 *cache,
107 *pixels;
108
cristy4c08aed2011-07-01 19:47:50 +0000109 void
110 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000111
cristybb503372010-05-27 20:51:26 +0000112 size_t
cristy3ed852e2009-09-05 21:47:34 +0000113 signature;
114};
115
116/*
117 Forward declarations.
118*/
119#if defined(__cplusplus) || defined(c_plusplus)
120extern "C" {
121#endif
122
cristy19596d62012-02-19 00:24:59 +0000123static Cache
124 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
125 magick_hot_spot;
126
cristy4c08aed2011-07-01 19:47:50 +0000127static const Quantum
cristybb503372010-05-27 20:51:26 +0000128 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000129 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 *GetVirtualPixelsCache(const Image *);
131
cristy4c08aed2011-07-01 19:47:50 +0000132static const void
133 *GetVirtualMetacontentFromCache(const Image *);
134
cristy3ed852e2009-09-05 21:47:34 +0000135static MagickBooleanType
cristy74ce05d2012-05-06 18:41:18 +0000136 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
137 ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000138 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000139 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000140 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000141 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
143 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000144 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000145 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
146
cristy4c08aed2011-07-01 19:47:50 +0000147static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000148 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
149 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000150 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
151 const size_t,ExceptionInfo *),
cristy265a2b22012-05-11 12:48:50 +0000152 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
153 NexusInfo *,ExceptionInfo *) magick_hot_spot;
cristy3ed852e2009-09-05 21:47:34 +0000154
155#if defined(__cplusplus) || defined(c_plusplus)
156}
157#endif
158
159/*
160 Global declarations.
161*/
162static volatile MagickBooleanType
163 instantiate_cache = MagickFalse;
164
165static SemaphoreInfo
166 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000167
168/*
169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170% %
171% %
172% %
173+ A c q u i r e P i x e l C a c h e %
174% %
175% %
176% %
177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178%
179% AcquirePixelCache() acquires a pixel cache.
180%
181% The format of the AcquirePixelCache() method is:
182%
cristybb503372010-05-27 20:51:26 +0000183% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184%
185% A description of each parameter follows:
186%
187% o number_threads: the number of nexus threads.
188%
189*/
cristya6577ff2011-09-02 19:54:26 +0000190MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000191{
192 CacheInfo
193 *cache_info;
194
cristya64b85d2011-09-14 01:02:31 +0000195 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000196 if (cache_info == (CacheInfo *) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
199 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000200 cache_info->mode=IOMode;
cristyc511e882012-04-16 21:11:14 +0000201 cache_info->colorspace=sRGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +0000202 cache_info->file=(-1);
203 cache_info->id=GetMagickThreadId();
204 cache_info->number_threads=number_threads;
205 if (number_threads == 0)
cristyfeeb98d2012-05-09 16:32:12 +0000206 cache_info->number_threads=GetOpenMPMaximumThreads();
cristy3ed852e2009-09-05 21:47:34 +0000207 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
208 if (cache_info->nexus_info == (NexusInfo **) NULL)
209 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000210 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000211 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000212 cache_info->disk_semaphore=AllocateSemaphoreInfo();
213 cache_info->debug=IsEventLogging();
214 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000215 return((Cache ) cache_info);
216}
217
218/*
219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220% %
221% %
222% %
223% A c q u i r e P i x e l C a c h e N e x u s %
224% %
225% %
226% %
227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228%
229% AcquirePixelCacheNexus() allocates the NexusInfo structure.
230%
231% The format of the AcquirePixelCacheNexus method is:
232%
cristybb503372010-05-27 20:51:26 +0000233% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000234%
235% A description of each parameter follows:
236%
237% o number_threads: the number of nexus threads.
238%
239*/
cristya6577ff2011-09-02 19:54:26 +0000240MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000241{
cristy3ed852e2009-09-05 21:47:34 +0000242 NexusInfo
243 **nexus_info;
244
cristye076a6e2010-08-15 19:59:43 +0000245 register ssize_t
246 i;
247
cristy64c3edf2012-04-13 18:50:13 +0000248 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000249 sizeof(*nexus_info));
250 if (nexus_info == (NexusInfo **) NULL)
251 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000252 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
253 sizeof(**nexus_info));
254 if (nexus_info[0] == (NexusInfo *) NULL)
255 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
256 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000257 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000258 {
cristye5f87c82012-02-14 12:44:17 +0000259 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000260 nexus_info[i]->signature=MagickSignature;
261 }
262 return(nexus_info);
263}
264
265/*
266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267% %
268% %
269% %
cristyd43a46b2010-01-21 02:13:41 +0000270+ A c q u i r e P i x e l C a c h e P i x e l s %
271% %
272% %
273% %
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275%
276% AcquirePixelCachePixels() returns the pixels associated with the specified
277% image.
278%
279% The format of the AcquirePixelCachePixels() method is:
280%
281% const void *AcquirePixelCachePixels(const Image *image,
282% MagickSizeType *length,ExceptionInfo *exception)
283%
284% A description of each parameter follows:
285%
286% o image: the image.
287%
288% o length: the pixel cache length.
289%
290% o exception: return any errors or warnings in this structure.
291%
292*/
cristyd1dd6e42011-09-04 01:46:08 +0000293MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000294 MagickSizeType *length,ExceptionInfo *exception)
295{
296 CacheInfo
297 *cache_info;
298
299 assert(image != (const Image *) NULL);
300 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000301 assert(exception != (ExceptionInfo *) NULL);
302 assert(exception->signature == MagickSignature);
303 assert(image->cache != (Cache) NULL);
304 cache_info=(CacheInfo *) image->cache;
305 assert(cache_info->signature == MagickSignature);
306 *length=0;
307 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
308 return((const void *) NULL);
309 *length=cache_info->length;
310 return((const void *) cache_info->pixels);
311}
312
313/*
314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315% %
316% %
317% %
cristyf34a1452009-10-24 22:29:27 +0000318+ C a c h e C o m p o n e n t G e n e s i s %
319% %
320% %
321% %
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323%
324% CacheComponentGenesis() instantiates the cache component.
325%
326% The format of the CacheComponentGenesis method is:
327%
328% MagickBooleanType CacheComponentGenesis(void)
329%
330*/
cristy5ff4eaf2011-09-03 01:38:02 +0000331MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000332{
cristy165b6092009-10-26 13:52:10 +0000333 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000334 return(MagickTrue);
335}
336
337/*
338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339% %
340% %
341% %
342+ C a c h e C o m p o n e n t T e r m i n u s %
343% %
344% %
345% %
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347%
348% CacheComponentTerminus() destroys the cache component.
349%
350% The format of the CacheComponentTerminus() method is:
351%
352% CacheComponentTerminus(void)
353%
354*/
cristy5ff4eaf2011-09-03 01:38:02 +0000355MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000356{
cristy18b17442009-10-25 18:36:48 +0000357 if (cache_semaphore == (SemaphoreInfo *) NULL)
358 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000359 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000360 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000361 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000362 DestroySemaphoreInfo(&cache_semaphore);
363}
364
365/*
366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
367% %
368% %
369% %
cristy3ed852e2009-09-05 21:47:34 +0000370+ C l o n e P i x e l C a c h e %
371% %
372% %
373% %
374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
375%
376% ClonePixelCache() clones a pixel cache.
377%
378% The format of the ClonePixelCache() method is:
379%
380% Cache ClonePixelCache(const Cache cache)
381%
382% A description of each parameter follows:
383%
384% o cache: the pixel cache.
385%
386*/
cristya6577ff2011-09-02 19:54:26 +0000387MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000388{
389 CacheInfo
390 *clone_info;
391
392 const CacheInfo
393 *cache_info;
394
cristy9f027d12011-09-21 01:17:17 +0000395 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000396 cache_info=(const CacheInfo *) cache;
397 assert(cache_info->signature == MagickSignature);
398 if (cache_info->debug != MagickFalse)
399 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
400 cache_info->filename);
401 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
402 if (clone_info == (Cache) NULL)
403 return((Cache) NULL);
404 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
405 return((Cache ) clone_info);
406}
407
408/*
409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
410% %
411% %
412% %
cristy60c44a82009-10-07 00:58:49 +0000413+ 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 +0000414% %
415% %
416% %
417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
418% ClonePixelCachePixels() clones the source pixel cache to the destination
419% cache.
420%
421% The format of the ClonePixelCachePixels() method is:
422%
423% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
424% CacheInfo *source_info,ExceptionInfo *exception)
425%
426% A description of each parameter follows:
427%
428% o cache_info: the pixel cache.
429%
430% o source_info: the source pixel cache.
431%
432% o exception: return any errors or warnings in this structure.
433%
434*/
435
436static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
437{
438 int
439 status;
440
cristy5ee247a2010-02-12 15:42:34 +0000441 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000442 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000443 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000444 {
445 status=close(cache_info->file);
446 cache_info->file=(-1);
447 RelinquishMagickResource(FileResource,1);
448 }
cristyf84a1932010-01-03 18:00:18 +0000449 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000450 return(status == -1 ? MagickFalse : MagickTrue);
451}
452
cristy3ed852e2009-09-05 21:47:34 +0000453static inline MagickSizeType MagickMax(const MagickSizeType x,
454 const MagickSizeType y)
455{
456 if (x > y)
457 return(x);
458 return(y);
459}
460
461static inline MagickSizeType MagickMin(const MagickSizeType x,
462 const MagickSizeType y)
463{
464 if (x < y)
465 return(x);
466 return(y);
467}
468
469static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
470 const MapMode mode)
471{
472 int
473 file;
474
475 /*
476 Open pixel cache on disk.
477 */
cristyf84a1932010-01-03 18:00:18 +0000478 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000479 if (cache_info->file != -1)
480 {
cristyf84a1932010-01-03 18:00:18 +0000481 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000482 return(MagickTrue); /* cache already open */
483 }
cristy3ed852e2009-09-05 21:47:34 +0000484 if (*cache_info->cache_filename == '\0')
485 file=AcquireUniqueFileResource(cache_info->cache_filename);
486 else
487 switch (mode)
488 {
489 case ReadMode:
490 {
cristy18c6c272011-09-23 14:40:37 +0000491 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000492 break;
493 }
494 case WriteMode:
495 {
cristy18c6c272011-09-23 14:40:37 +0000496 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
497 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000498 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000499 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000500 break;
501 }
502 case IOMode:
503 default:
504 {
cristy18c6c272011-09-23 14:40:37 +0000505 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000506 O_EXCL,S_MODE);
507 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000508 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000509 break;
510 }
511 }
512 if (file == -1)
513 {
cristyf84a1932010-01-03 18:00:18 +0000514 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000515 return(MagickFalse);
516 }
517 (void) AcquireMagickResource(FileResource,1);
518 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000519 cache_info->mode=mode;
cristyf84a1932010-01-03 18:00:18 +0000520 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000521 return(MagickTrue);
522}
523
cristyf1832792012-05-08 18:38:18 +0000524static inline MagickOffsetType ReadPixelCacheRegion(
525 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
526 const MagickSizeType length,unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000527{
528 register MagickOffsetType
529 i;
530
531 ssize_t
532 count;
533
534#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000535 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000536 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000537 {
cristyf84a1932010-01-03 18:00:18 +0000538 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000539 return((MagickOffsetType) -1);
540 }
541#endif
542 count=0;
543 for (i=0; i < (MagickOffsetType) length; i+=count)
544 {
545#if !defined(MAGICKCORE_HAVE_PREAD)
546 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
547 (MagickSizeType) SSIZE_MAX));
548#else
549 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000550 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000551#endif
552 if (count > 0)
553 continue;
554 count=0;
555 if (errno != EINTR)
556 {
557 i=(-1);
558 break;
559 }
560 }
561#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563#endif
564 return(i);
565}
566
cristyf1832792012-05-08 18:38:18 +0000567static inline MagickOffsetType WritePixelCacheRegion(
568 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
569 const MagickSizeType length,const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000570{
571 register MagickOffsetType
572 i;
573
574 ssize_t
575 count;
576
577#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000578 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000579 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000580 {
cristyf84a1932010-01-03 18:00:18 +0000581 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000582 return((MagickOffsetType) -1);
583 }
584#endif
585 count=0;
586 for (i=0; i < (MagickOffsetType) length; i+=count)
587 {
588#if !defined(MAGICKCORE_HAVE_PWRITE)
589 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
590 (MagickSizeType) SSIZE_MAX));
591#else
592 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000593 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000594#endif
595 if (count > 0)
596 continue;
597 count=0;
598 if (errno != EINTR)
599 {
600 i=(-1);
601 break;
602 }
603 }
604#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000605 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000606#endif
607 return(i);
608}
609
cristy4c08aed2011-07-01 19:47:50 +0000610static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000611 CacheInfo *cache_info,ExceptionInfo *exception)
612{
613 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000614 count;
cristy3ed852e2009-09-05 21:47:34 +0000615
cristy4c08aed2011-07-01 19:47:50 +0000616 register MagickOffsetType
617 i;
cristye076a6e2010-08-15 19:59:43 +0000618
cristybb503372010-05-27 20:51:26 +0000619 size_t
cristy4c08aed2011-07-01 19:47:50 +0000620 length;
cristy3ed852e2009-09-05 21:47:34 +0000621
cristy4c08aed2011-07-01 19:47:50 +0000622 unsigned char
623 *blob;
624
625 /*
626 Clone pixel cache (both caches on disk).
627 */
cristy3ed852e2009-09-05 21:47:34 +0000628 if (cache_info->debug != MagickFalse)
629 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000630 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000631 sizeof(*blob));
632 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000633 {
cristy4c08aed2011-07-01 19:47:50 +0000634 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000635 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000636 cache_info->filename);
637 return(MagickFalse);
638 }
cristy3dedf062011-07-02 14:07:40 +0000639 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000640 {
641 blob=(unsigned char *) RelinquishMagickMemory(blob);
642 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
643 cache_info->cache_filename);
644 return(MagickFalse);
645 }
cristy3dedf062011-07-02 14:07:40 +0000646 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000647 {
648 (void) ClosePixelCacheOnDisk(cache_info);
649 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000650 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
651 clone_info->cache_filename);
652 return(MagickFalse);
653 }
cristy4c08aed2011-07-01 19:47:50 +0000654 count=0;
655 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000656 {
cristy4c08aed2011-07-01 19:47:50 +0000657 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
658 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
659 blob);
660 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000661 {
cristy4c08aed2011-07-01 19:47:50 +0000662 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
663 cache_info->cache_filename);
664 break;
cristy3ed852e2009-09-05 21:47:34 +0000665 }
cristy4c08aed2011-07-01 19:47:50 +0000666 length=(size_t) count;
667 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
668 if ((MagickSizeType) count != length)
669 {
670 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
671 clone_info->cache_filename);
672 break;
673 }
674 }
675 (void) ClosePixelCacheOnDisk(clone_info);
676 (void) ClosePixelCacheOnDisk(cache_info);
677 blob=(unsigned char *) RelinquishMagickMemory(blob);
678 if (i < (MagickOffsetType) cache_info->length)
679 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000680 return(MagickTrue);
681}
682
cristyfd24a062012-01-02 14:46:34 +0000683static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000684 CacheInfo *cache_info,ExceptionInfo *exception)
685{
686 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000687 count;
cristy3ed852e2009-09-05 21:47:34 +0000688
cristy4c08aed2011-07-01 19:47:50 +0000689 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000690 {
cristy3ed852e2009-09-05 21:47:34 +0000691 /*
cristy4c08aed2011-07-01 19:47:50 +0000692 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000693 */
cristy4c08aed2011-07-01 19:47:50 +0000694 if (cache_info->debug != MagickFalse)
695 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
696 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
697 cache_info->length);
698 return(MagickTrue);
699 }
700 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
701 {
702 /*
703 Clone pixel cache (one cache on disk, one in memory).
704 */
705 if (cache_info->debug != MagickFalse)
706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
707 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000708 {
cristy4c08aed2011-07-01 19:47:50 +0000709 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000710 cache_info->cache_filename);
711 return(MagickFalse);
712 }
cristy4c08aed2011-07-01 19:47:50 +0000713 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
714 cache_info->length,(unsigned char *) clone_info->pixels);
715 (void) ClosePixelCacheOnDisk(cache_info);
716 if ((MagickSizeType) count != cache_info->length)
717 {
718 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
719 cache_info->cache_filename);
720 return(MagickFalse);
721 }
722 return(MagickTrue);
723 }
724 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
725 {
726 /*
727 Clone pixel cache (one cache on disk, one in memory).
728 */
729 if (clone_info->debug != MagickFalse)
730 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
731 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
732 {
733 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
734 clone_info->cache_filename);
735 return(MagickFalse);
736 }
737 count=WritePixelCacheRegion(clone_info,clone_info->offset,
738 clone_info->length,(unsigned char *) cache_info->pixels);
739 (void) ClosePixelCacheOnDisk(clone_info);
740 if ((MagickSizeType) count != clone_info->length)
741 {
742 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
743 clone_info->cache_filename);
744 return(MagickFalse);
745 }
746 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000747 }
748 /*
cristy4c08aed2011-07-01 19:47:50 +0000749 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000750 */
cristy4c08aed2011-07-01 19:47:50 +0000751 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000752}
753
cristyfd24a062012-01-02 14:46:34 +0000754static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000755 CacheInfo *cache_info,ExceptionInfo *exception)
756{
cristy4c08aed2011-07-01 19:47:50 +0000757 MagickBooleanType
758 status;
cristy3ed852e2009-09-05 21:47:34 +0000759
cristy4c08aed2011-07-01 19:47:50 +0000760 MagickOffsetType
761 cache_offset,
762 clone_offset,
763 count;
764
765 register ssize_t
766 x;
767
cristyfd24a062012-01-02 14:46:34 +0000768 register unsigned char
769 *p;
770
cristy4c08aed2011-07-01 19:47:50 +0000771 size_t
cristy3ed852e2009-09-05 21:47:34 +0000772 length;
773
cristy4c08aed2011-07-01 19:47:50 +0000774 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000775 y;
776
cristy4c08aed2011-07-01 19:47:50 +0000777 unsigned char
778 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000779
cristy4c08aed2011-07-01 19:47:50 +0000780 /*
781 Clone pixel cache (unoptimized).
782 */
cristy3ed852e2009-09-05 21:47:34 +0000783 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000784 {
cristy4c08aed2011-07-01 19:47:50 +0000785 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
787 else
788 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
789 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
790 else
791 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
792 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
793 else
794 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
795 }
cristyed231572011-07-14 02:18:59 +0000796 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
797 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000798 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000799 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000800 if (blob == (unsigned char *) NULL)
801 {
802 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000803 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000804 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000805 return(MagickFalse);
806 }
cristy4c08aed2011-07-01 19:47:50 +0000807 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
808 cache_offset=0;
809 clone_offset=0;
810 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000811 {
cristy4c08aed2011-07-01 19:47:50 +0000812 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000813 {
cristy4c08aed2011-07-01 19:47:50 +0000814 blob=(unsigned char *) RelinquishMagickMemory(blob);
815 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000816 cache_info->cache_filename);
817 return(MagickFalse);
818 }
cristy4c08aed2011-07-01 19:47:50 +0000819 cache_offset=cache_info->offset;
820 }
821 if (clone_info->type == DiskCache)
822 {
cristy3dedf062011-07-02 14:07:40 +0000823 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000824 {
cristy4c08aed2011-07-01 19:47:50 +0000825 blob=(unsigned char *) RelinquishMagickMemory(blob);
826 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
827 clone_info->cache_filename);
828 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000829 }
cristy4c08aed2011-07-01 19:47:50 +0000830 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000831 }
832 /*
cristy4c08aed2011-07-01 19:47:50 +0000833 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000834 */
cristy4c08aed2011-07-01 19:47:50 +0000835 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000836 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000837 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000838 {
cristy4c08aed2011-07-01 19:47:50 +0000839 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000840 {
cristy9e0719b2011-12-29 03:45:45 +0000841 register ssize_t
842 i;
843
cristy3ed852e2009-09-05 21:47:34 +0000844 /*
cristy4c08aed2011-07-01 19:47:50 +0000845 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000846 */
cristyed231572011-07-14 02:18:59 +0000847 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000848 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000849 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000850 else
851 {
cristyfd24a062012-01-02 14:46:34 +0000852 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000853 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000854 {
cristy4c08aed2011-07-01 19:47:50 +0000855 status=MagickFalse;
856 break;
cristy3ed852e2009-09-05 21:47:34 +0000857 }
858 }
cristy4c08aed2011-07-01 19:47:50 +0000859 cache_offset+=length;
860 if ((y < (ssize_t) clone_info->rows) &&
861 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000862 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000863 {
cristy9e0719b2011-12-29 03:45:45 +0000864 PixelChannel
865 channel;
866
867 PixelTrait
868 traits;
869
870 ssize_t
871 offset;
872
cristy4c08aed2011-07-01 19:47:50 +0000873 /*
cristy3b8fe922011-12-29 18:56:23 +0000874 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000875 */
cristy9e0719b2011-12-29 03:45:45 +0000876 channel=clone_info->channel_map[i].channel;
877 traits=cache_info->channel_map[channel].traits;
878 if (traits == UndefinedPixelTrait)
879 {
cristy0f4425e2011-12-31 20:33:02 +0000880 clone_offset+=sizeof(Quantum);
881 continue;
cristy9e0719b2011-12-29 03:45:45 +0000882 }
cristy0f4425e2011-12-31 20:33:02 +0000883 offset=cache_info->channel_map[channel].offset;
884 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000885 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
886 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000887 else
888 {
cristy0f4425e2011-12-31 20:33:02 +0000889 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000890 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000891 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000892 {
cristy0f4425e2011-12-31 20:33:02 +0000893 status=MagickFalse;
894 break;
cristy4c08aed2011-07-01 19:47:50 +0000895 }
896 }
cristy9e0719b2011-12-29 03:45:45 +0000897 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000898 }
899 }
cristyac245f82012-05-05 17:13:57 +0000900 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000901 {
902 /*
903 Set remaining columns as undefined.
904 */
cristy888e6132012-04-23 19:54:54 +0000905 length=clone_info->number_channels*sizeof(Quantum);
906 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
907 for ( ; x < (ssize_t) clone_info->columns; x++)
908 {
909 if (clone_info->type != DiskCache)
910 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
911 blob,length);
912 else
913 {
914 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
915 if ((MagickSizeType) count != length)
916 {
917 status=MagickFalse;
918 break;
cristye04362f2012-04-23 15:33:05 +0000919 }
cristy888e6132012-04-23 19:54:54 +0000920 }
921 clone_offset+=length;
922 }
cristye04362f2012-04-23 15:33:05 +0000923 }
cristy4c08aed2011-07-01 19:47:50 +0000924 }
cristyed231572011-07-14 02:18:59 +0000925 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000926 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
927 for ( ; y < (ssize_t) clone_info->rows; y++)
928 {
929 /*
cristy9e0719b2011-12-29 03:45:45 +0000930 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000931 */
932 for (x=0; x < (ssize_t) clone_info->columns; x++)
933 {
934 if (clone_info->type != DiskCache)
935 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
936 length);
937 else
938 {
939 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
940 if ((MagickSizeType) count != length)
941 {
942 status=MagickFalse;
943 break;
944 }
945 }
946 clone_offset+=length;
947 }
948 }
cristy9e0719b2011-12-29 03:45:45 +0000949 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000950 (clone_info->metacontent_extent != 0))
951 {
952 /*
953 Clone metacontent.
954 */
955 for (y=0; y < (ssize_t) cache_info->rows; y++)
956 {
957 for (x=0; x < (ssize_t) cache_info->columns; x++)
958 {
959 /*
960 Read a set of metacontent.
961 */
962 length=cache_info->metacontent_extent;
963 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000964 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000965 else
966 {
cristyfd24a062012-01-02 14:46:34 +0000967 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000968 if ((MagickSizeType) count != length)
969 {
970 status=MagickFalse;
971 break;
972 }
973 }
974 cache_offset+=length;
975 if ((y < (ssize_t) clone_info->rows) &&
976 (x < (ssize_t) clone_info->columns))
977 {
978 /*
979 Write a set of metacontent.
980 */
981 length=clone_info->metacontent_extent;
982 if (clone_info->type != DiskCache)
983 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000984 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000985 else
986 {
cristyfd24a062012-01-02 14:46:34 +0000987 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000988 if ((MagickSizeType) count != length)
989 {
990 status=MagickFalse;
991 break;
992 }
993 }
994 clone_offset+=length;
995 }
996 }
997 length=clone_info->metacontent_extent;
998 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
999 for ( ; x < (ssize_t) clone_info->columns; x++)
1000 {
1001 /*
cristy9e0719b2011-12-29 03:45:45 +00001002 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001003 */
1004 if (clone_info->type != DiskCache)
1005 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1006 blob,length);
1007 else
1008 {
cristy208b1002011-08-07 18:51:50 +00001009 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001010 if ((MagickSizeType) count != length)
1011 {
1012 status=MagickFalse;
1013 break;
1014 }
1015 }
1016 clone_offset+=length;
1017 }
1018 }
cristyac245f82012-05-05 17:13:57 +00001019 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001020 {
cristye04362f2012-04-23 15:33:05 +00001021 /*
1022 Set remaining rows as undefined.
1023 */
cristy888e6132012-04-23 19:54:54 +00001024 length=clone_info->metacontent_extent;
1025 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1026 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001027 {
cristy888e6132012-04-23 19:54:54 +00001028 for (x=0; x < (ssize_t) clone_info->columns; x++)
1029 {
1030 if (clone_info->type != DiskCache)
1031 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1032 blob,length);
1033 else
1034 {
1035 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1036 blob);
1037 if ((MagickSizeType) count != length)
1038 {
1039 status=MagickFalse;
1040 break;
1041 }
1042 }
1043 clone_offset+=length;
1044 }
cristye04362f2012-04-23 15:33:05 +00001045 }
cristy4c08aed2011-07-01 19:47:50 +00001046 }
cristy4c08aed2011-07-01 19:47:50 +00001047 }
1048 if (clone_info->type == DiskCache)
1049 (void) ClosePixelCacheOnDisk(clone_info);
1050 if (cache_info->type == DiskCache)
1051 (void) ClosePixelCacheOnDisk(cache_info);
1052 blob=(unsigned char *) RelinquishMagickMemory(blob);
1053 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001054}
1055
1056static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1057 CacheInfo *cache_info,ExceptionInfo *exception)
1058{
cristy3dfccb22011-12-28 21:47:20 +00001059 PixelChannelMap
1060 *p,
1061 *q;
1062
cristy5a7fbfb2010-11-06 16:10:59 +00001063 if (cache_info->type == PingCache)
1064 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001065 p=cache_info->channel_map;
1066 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001067 if ((cache_info->columns == clone_info->columns) &&
1068 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001069 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001070 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001071 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001072 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1073 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001074}
1075
1076/*
1077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078% %
1079% %
1080% %
1081+ C l o n e P i x e l C a c h e M e t h o d s %
1082% %
1083% %
1084% %
1085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086%
1087% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1088% another.
1089%
1090% The format of the ClonePixelCacheMethods() method is:
1091%
1092% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1093%
1094% A description of each parameter follows:
1095%
1096% o clone: Specifies a pointer to a Cache structure.
1097%
1098% o cache: the pixel cache.
1099%
1100*/
cristya6577ff2011-09-02 19:54:26 +00001101MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001102{
1103 CacheInfo
1104 *cache_info,
1105 *source_info;
1106
1107 assert(clone != (Cache) NULL);
1108 source_info=(CacheInfo *) clone;
1109 assert(source_info->signature == MagickSignature);
1110 if (source_info->debug != MagickFalse)
1111 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1112 source_info->filename);
1113 assert(cache != (Cache) NULL);
1114 cache_info=(CacheInfo *) cache;
1115 assert(cache_info->signature == MagickSignature);
1116 source_info->methods=cache_info->methods;
1117}
1118
1119/*
1120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1121% %
1122% %
1123% %
1124+ D e s t r o y I m a g e P i x e l C a c h e %
1125% %
1126% %
1127% %
1128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1129%
1130% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1131%
1132% The format of the DestroyImagePixelCache() method is:
1133%
1134% void DestroyImagePixelCache(Image *image)
1135%
1136% A description of each parameter follows:
1137%
1138% o image: the image.
1139%
1140*/
1141static void DestroyImagePixelCache(Image *image)
1142{
1143 assert(image != (Image *) NULL);
1144 assert(image->signature == MagickSignature);
1145 if (image->debug != MagickFalse)
1146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1147 if (image->cache == (void *) NULL)
1148 return;
1149 image->cache=DestroyPixelCache(image->cache);
1150}
1151
1152/*
1153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1154% %
1155% %
1156% %
1157+ D e s t r o y I m a g e P i x e l s %
1158% %
1159% %
1160% %
1161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162%
1163% DestroyImagePixels() deallocates memory associated with the pixel cache.
1164%
1165% The format of the DestroyImagePixels() method is:
1166%
1167% void DestroyImagePixels(Image *image)
1168%
1169% A description of each parameter follows:
1170%
1171% o image: the image.
1172%
1173*/
1174MagickExport void DestroyImagePixels(Image *image)
1175{
1176 CacheInfo
1177 *cache_info;
1178
1179 assert(image != (const Image *) NULL);
1180 assert(image->signature == MagickSignature);
1181 if (image->debug != MagickFalse)
1182 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1183 assert(image->cache != (Cache) NULL);
1184 cache_info=(CacheInfo *) image->cache;
1185 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001186 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1187 {
1188 cache_info->methods.destroy_pixel_handler(image);
1189 return;
1190 }
cristy2036f5c2010-09-19 21:18:17 +00001191 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001192}
1193
1194/*
1195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1196% %
1197% %
1198% %
1199+ D e s t r o y P i x e l C a c h e %
1200% %
1201% %
1202% %
1203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1204%
1205% DestroyPixelCache() deallocates memory associated with the pixel cache.
1206%
1207% The format of the DestroyPixelCache() method is:
1208%
1209% Cache DestroyPixelCache(Cache cache)
1210%
1211% A description of each parameter follows:
1212%
1213% o cache: the pixel cache.
1214%
1215*/
1216
1217static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1218{
1219 switch (cache_info->type)
1220 {
1221 case MemoryCache:
1222 {
1223 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001224 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001225 cache_info->pixels);
1226 else
cristy4c08aed2011-07-01 19:47:50 +00001227 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001228 (size_t) cache_info->length);
1229 RelinquishMagickResource(MemoryResource,cache_info->length);
1230 break;
1231 }
1232 case MapCache:
1233 {
cristy4c08aed2011-07-01 19:47:50 +00001234 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001235 cache_info->length);
1236 RelinquishMagickResource(MapResource,cache_info->length);
1237 }
1238 case DiskCache:
1239 {
1240 if (cache_info->file != -1)
1241 (void) ClosePixelCacheOnDisk(cache_info);
1242 RelinquishMagickResource(DiskResource,cache_info->length);
1243 break;
1244 }
1245 default:
1246 break;
1247 }
1248 cache_info->type=UndefinedCache;
1249 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001250 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001251}
1252
cristya6577ff2011-09-02 19:54:26 +00001253MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001254{
1255 CacheInfo
1256 *cache_info;
1257
cristy3ed852e2009-09-05 21:47:34 +00001258 assert(cache != (Cache) NULL);
1259 cache_info=(CacheInfo *) cache;
1260 assert(cache_info->signature == MagickSignature);
1261 if (cache_info->debug != MagickFalse)
1262 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1263 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001264 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001265 cache_info->reference_count--;
1266 if (cache_info->reference_count != 0)
1267 {
cristyf84a1932010-01-03 18:00:18 +00001268 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001269 return((Cache) NULL);
1270 }
cristyf84a1932010-01-03 18:00:18 +00001271 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001272 if (cache_info->debug != MagickFalse)
1273 {
1274 char
1275 message[MaxTextExtent];
1276
cristyb51dff52011-05-19 16:55:47 +00001277 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001278 cache_info->filename);
1279 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1280 }
cristyc2e1bdd2009-09-10 23:43:34 +00001281 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1282 (cache_info->type != DiskCache)))
1283 RelinquishPixelCachePixels(cache_info);
1284 else
1285 {
1286 RelinquishPixelCachePixels(cache_info);
1287 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1288 }
cristy3ed852e2009-09-05 21:47:34 +00001289 *cache_info->cache_filename='\0';
1290 if (cache_info->nexus_info != (NexusInfo **) NULL)
1291 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1292 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001293 if (cache_info->random_info != (RandomInfo *) NULL)
1294 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001295 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1296 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1297 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1298 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001299 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001300 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001301 cache=(Cache) NULL;
1302 return(cache);
1303}
1304
1305/*
1306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307% %
1308% %
1309% %
1310+ D e s t r o y P i x e l C a c h e N e x u s %
1311% %
1312% %
1313% %
1314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1315%
1316% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1317%
1318% The format of the DestroyPixelCacheNexus() method is:
1319%
1320% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001321% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001322%
1323% A description of each parameter follows:
1324%
1325% o nexus_info: the nexus to destroy.
1326%
1327% o number_threads: the number of nexus threads.
1328%
1329*/
1330
1331static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1332{
1333 if (nexus_info->mapped == MagickFalse)
cristy64c3edf2012-04-13 18:50:13 +00001334 (void) RelinquishMagickMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001335 else
1336 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001337 nexus_info->cache=(Quantum *) NULL;
1338 nexus_info->pixels=(Quantum *) NULL;
1339 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001340 nexus_info->length=0;
1341 nexus_info->mapped=MagickFalse;
1342}
1343
cristya6577ff2011-09-02 19:54:26 +00001344MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001345 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001346{
cristybb503372010-05-27 20:51:26 +00001347 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001348 i;
1349
1350 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001351 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001352 {
cristy4c08aed2011-07-01 19:47:50 +00001353 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001354 RelinquishCacheNexusPixels(nexus_info[i]);
1355 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001356 }
cristye5f87c82012-02-14 12:44:17 +00001357 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001358 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001359 return(nexus_info);
1360}
1361
1362/*
1363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364% %
1365% %
1366% %
cristy4c08aed2011-07-01 19:47:50 +00001367% 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 +00001368% %
1369% %
1370% %
1371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372%
cristy4c08aed2011-07-01 19:47:50 +00001373% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1374% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1375% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001376%
cristy4c08aed2011-07-01 19:47:50 +00001377% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001378%
cristy4c08aed2011-07-01 19:47:50 +00001379% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001380%
1381% A description of each parameter follows:
1382%
1383% o image: the image.
1384%
1385*/
cristy4c08aed2011-07-01 19:47:50 +00001386MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001387{
1388 CacheInfo
1389 *cache_info;
1390
cristy5c9e6f22010-09-17 17:31:01 +00001391 const int
1392 id = GetOpenMPThreadId();
1393
cristy4c08aed2011-07-01 19:47:50 +00001394 void
1395 *metacontent;
1396
cristye7cc7cf2010-09-21 13:26:47 +00001397 assert(image != (const Image *) NULL);
1398 assert(image->signature == MagickSignature);
1399 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001400 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001401 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001402 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1403 (GetAuthenticMetacontentFromHandler) NULL)
1404 {
1405 metacontent=cache_info->methods.
1406 get_authentic_metacontent_from_handler(image);
1407 return(metacontent);
1408 }
cristy6ebe97c2010-07-03 01:17:28 +00001409 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001410 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1411 cache_info->nexus_info[id]);
1412 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001413}
1414
1415/*
1416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1417% %
1418% %
1419% %
cristy4c08aed2011-07-01 19:47:50 +00001420+ 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 +00001421% %
1422% %
1423% %
1424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1425%
cristy4c08aed2011-07-01 19:47:50 +00001426% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1427% with the last call to QueueAuthenticPixelsCache() or
1428% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001429%
cristy4c08aed2011-07-01 19:47:50 +00001430% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001431%
cristy4c08aed2011-07-01 19:47:50 +00001432% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001433%
1434% A description of each parameter follows:
1435%
1436% o image: the image.
1437%
1438*/
cristy4c08aed2011-07-01 19:47:50 +00001439static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001440{
1441 CacheInfo
1442 *cache_info;
1443
cristy2036f5c2010-09-19 21:18:17 +00001444 const int
1445 id = GetOpenMPThreadId();
1446
cristy4c08aed2011-07-01 19:47:50 +00001447 void
1448 *metacontent;
1449
cristy3ed852e2009-09-05 21:47:34 +00001450 assert(image != (const Image *) NULL);
1451 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001452 assert(image->cache != (Cache) NULL);
1453 cache_info=(CacheInfo *) image->cache;
1454 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001455 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001456 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1457 cache_info->nexus_info[id]);
1458 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001459}
1460
1461/*
1462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1463% %
1464% %
1465% %
1466+ 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 %
1467% %
1468% %
1469% %
1470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1471%
1472% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1473% disk pixel cache as defined by the geometry parameters. A pointer to the
1474% pixels is returned if the pixels are transferred, otherwise a NULL is
1475% returned.
1476%
1477% The format of the GetAuthenticPixelCacheNexus() method is:
1478%
cristy4c08aed2011-07-01 19:47:50 +00001479% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001480% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001481% NexusInfo *nexus_info,ExceptionInfo *exception)
1482%
1483% A description of each parameter follows:
1484%
1485% o image: the image.
1486%
1487% o x,y,columns,rows: These values define the perimeter of a region of
1488% pixels.
1489%
1490% o nexus_info: the cache nexus to return.
1491%
1492% o exception: return any errors or warnings in this structure.
1493%
1494*/
1495
cristy7f69b802012-05-08 16:39:59 +00001496static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001497 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001498{
cristy4c08aed2011-07-01 19:47:50 +00001499 MagickBooleanType
1500 status;
1501
cristy3ed852e2009-09-05 21:47:34 +00001502 MagickOffsetType
1503 offset;
1504
cristy73724512010-04-12 14:43:14 +00001505 if (cache_info->type == PingCache)
1506 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001507 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1508 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001509 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001510 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001511 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001512}
1513
cristya6577ff2011-09-02 19:54:26 +00001514MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001515 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001516 NexusInfo *nexus_info,ExceptionInfo *exception)
1517{
1518 CacheInfo
1519 *cache_info;
1520
cristy4c08aed2011-07-01 19:47:50 +00001521 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001522 *q;
cristy3ed852e2009-09-05 21:47:34 +00001523
1524 /*
1525 Transfer pixels from the cache.
1526 */
1527 assert(image != (Image *) NULL);
1528 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001529 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1530 exception);
cristyacd2ed22011-08-30 01:44:23 +00001531 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001532 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001533 cache_info=(CacheInfo *) image->cache;
1534 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001535 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001536 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001537 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001538 return((Quantum *) NULL);
1539 if (cache_info->metacontent_extent != 0)
1540 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1541 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001542 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001543}
1544
1545/*
1546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547% %
1548% %
1549% %
1550+ 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 %
1551% %
1552% %
1553% %
1554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555%
1556% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1557% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1558%
1559% The format of the GetAuthenticPixelsFromCache() method is:
1560%
cristy4c08aed2011-07-01 19:47:50 +00001561% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001562%
1563% A description of each parameter follows:
1564%
1565% o image: the image.
1566%
1567*/
cristy4c08aed2011-07-01 19:47:50 +00001568static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001569{
1570 CacheInfo
1571 *cache_info;
1572
cristy5c9e6f22010-09-17 17:31:01 +00001573 const int
1574 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001575
cristye7cc7cf2010-09-21 13:26:47 +00001576 assert(image != (const Image *) NULL);
1577 assert(image->signature == MagickSignature);
1578 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001579 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001580 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001581 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001582 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001583}
1584
1585/*
1586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587% %
1588% %
1589% %
1590% G e t A u t h e n t i c P i x e l Q u e u e %
1591% %
1592% %
1593% %
1594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595%
cristy4c08aed2011-07-01 19:47:50 +00001596% GetAuthenticPixelQueue() returns the authentic pixels associated
1597% corresponding with the last call to QueueAuthenticPixels() or
1598% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001599%
1600% The format of the GetAuthenticPixelQueue() method is:
1601%
cristy4c08aed2011-07-01 19:47:50 +00001602% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001603%
1604% A description of each parameter follows:
1605%
1606% o image: the image.
1607%
1608*/
cristy4c08aed2011-07-01 19:47:50 +00001609MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001610{
1611 CacheInfo
1612 *cache_info;
1613
cristy2036f5c2010-09-19 21:18:17 +00001614 const int
1615 id = GetOpenMPThreadId();
1616
cristy3ed852e2009-09-05 21:47:34 +00001617 assert(image != (const Image *) NULL);
1618 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001619 assert(image->cache != (Cache) NULL);
1620 cache_info=(CacheInfo *) image->cache;
1621 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001622 if (cache_info->methods.get_authentic_pixels_from_handler !=
1623 (GetAuthenticPixelsFromHandler) NULL)
1624 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001625 assert(id < (int) cache_info->number_threads);
1626 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001627}
1628
1629/*
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631% %
1632% %
1633% %
1634% G e t A u t h e n t i c P i x e l s %
1635% %
1636% %
cristy4c08aed2011-07-01 19:47:50 +00001637% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001638%
1639% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001640% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001641% representing the region is returned, otherwise NULL is returned.
1642%
1643% The returned pointer may point to a temporary working copy of the pixels
1644% or it may point to the original pixels in memory. Performance is maximized
1645% if the selected region is part of one row, or one or more full rows, since
1646% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001647% if the image is in memory, or in a memory-mapped file. The returned pointer
1648% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001649%
1650% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001651% Quantum. If the image has corresponding metacontent,call
1652% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1653% meta-content corresponding to the region. Once the Quantum array has
1654% been updated, the changes must be saved back to the underlying image using
1655% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001656%
1657% The format of the GetAuthenticPixels() method is:
1658%
cristy4c08aed2011-07-01 19:47:50 +00001659% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001660% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001661% ExceptionInfo *exception)
1662%
1663% A description of each parameter follows:
1664%
1665% o image: the image.
1666%
1667% o x,y,columns,rows: These values define the perimeter of a region of
1668% pixels.
1669%
1670% o exception: return any errors or warnings in this structure.
1671%
1672*/
cristy4c08aed2011-07-01 19:47:50 +00001673MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001674 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001675 ExceptionInfo *exception)
1676{
1677 CacheInfo
1678 *cache_info;
1679
cristy2036f5c2010-09-19 21:18:17 +00001680 const int
1681 id = GetOpenMPThreadId();
1682
cristy4c08aed2011-07-01 19:47:50 +00001683 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001684 *q;
cristy4c08aed2011-07-01 19:47:50 +00001685
cristy3ed852e2009-09-05 21:47:34 +00001686 assert(image != (Image *) NULL);
1687 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001688 assert(image->cache != (Cache) NULL);
1689 cache_info=(CacheInfo *) image->cache;
1690 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001691 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001692 (GetAuthenticPixelsHandler) NULL)
1693 {
cristyacd2ed22011-08-30 01:44:23 +00001694 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1695 exception);
1696 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001697 }
cristy2036f5c2010-09-19 21:18:17 +00001698 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001699 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001700 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001701 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001702}
1703
1704/*
1705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1706% %
1707% %
1708% %
1709+ G e t A u t h e n t i c P i x e l s C a c h e %
1710% %
1711% %
1712% %
1713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1714%
1715% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1716% as defined by the geometry parameters. A pointer to the pixels is returned
1717% if the pixels are transferred, otherwise a NULL is returned.
1718%
1719% The format of the GetAuthenticPixelsCache() method is:
1720%
cristy4c08aed2011-07-01 19:47:50 +00001721% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001722% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001723% ExceptionInfo *exception)
1724%
1725% A description of each parameter follows:
1726%
1727% o image: the image.
1728%
1729% o x,y,columns,rows: These values define the perimeter of a region of
1730% pixels.
1731%
1732% o exception: return any errors or warnings in this structure.
1733%
1734*/
cristy4c08aed2011-07-01 19:47:50 +00001735static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001736 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001737 ExceptionInfo *exception)
1738{
1739 CacheInfo
1740 *cache_info;
1741
cristy5c9e6f22010-09-17 17:31:01 +00001742 const int
1743 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001744
cristy4c08aed2011-07-01 19:47:50 +00001745 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001746 *q;
cristy4c08aed2011-07-01 19:47:50 +00001747
cristye7cc7cf2010-09-21 13:26:47 +00001748 assert(image != (const Image *) NULL);
1749 assert(image->signature == MagickSignature);
1750 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001751 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001752 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001753 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001754 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001755 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001756 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001757 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001758 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001759}
1760
1761/*
1762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763% %
1764% %
1765% %
1766+ G e t I m a g e E x t e n t %
1767% %
1768% %
1769% %
1770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1771%
cristy4c08aed2011-07-01 19:47:50 +00001772% GetImageExtent() returns the extent of the pixels associated corresponding
1773% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001774%
1775% The format of the GetImageExtent() method is:
1776%
1777% MagickSizeType GetImageExtent(const Image *image)
1778%
1779% A description of each parameter follows:
1780%
1781% o image: the image.
1782%
1783*/
1784MagickExport MagickSizeType GetImageExtent(const Image *image)
1785{
1786 CacheInfo
1787 *cache_info;
1788
cristy5c9e6f22010-09-17 17:31:01 +00001789 const int
1790 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001791
cristy3ed852e2009-09-05 21:47:34 +00001792 assert(image != (Image *) NULL);
1793 assert(image->signature == MagickSignature);
1794 if (image->debug != MagickFalse)
1795 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1796 assert(image->cache != (Cache) NULL);
1797 cache_info=(CacheInfo *) image->cache;
1798 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001799 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001800 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001801}
1802
1803/*
1804%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1805% %
1806% %
1807% %
1808+ G e t I m a g e P i x e l C a c h e %
1809% %
1810% %
1811% %
1812%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1813%
1814% GetImagePixelCache() ensures that there is only a single reference to the
1815% pixel cache to be modified, updating the provided cache pointer to point to
1816% a clone of the original pixel cache if necessary.
1817%
1818% The format of the GetImagePixelCache method is:
1819%
1820% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1821% ExceptionInfo *exception)
1822%
1823% A description of each parameter follows:
1824%
1825% o image: the image.
1826%
1827% o clone: any value other than MagickFalse clones the cache pixels.
1828%
1829% o exception: return any errors or warnings in this structure.
1830%
1831*/
cristyaf894d72011-08-06 23:03:10 +00001832
cristyf1832792012-05-08 18:38:18 +00001833static inline MagickBooleanType ValidatePixelCacheMorphology(
1834 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001835{
cristyf1832792012-05-08 18:38:18 +00001836 const CacheInfo
1837 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001838
cristyf1832792012-05-08 18:38:18 +00001839 const PixelChannelMap
1840 *restrict p,
1841 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001842
cristy3ed852e2009-09-05 21:47:34 +00001843 /*
1844 Does the image match the pixel cache morphology?
1845 */
1846 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001847 p=image->channel_map;
1848 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001849 if ((image->storage_class != cache_info->storage_class) ||
1850 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001851 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001852 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001853 (image->columns != cache_info->columns) ||
1854 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001855 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001856 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001857 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001858 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001859 return(MagickFalse);
1860 return(MagickTrue);
1861}
1862
cristycd01fae2011-08-06 23:52:42 +00001863static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1864 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001865{
1866 CacheInfo
1867 *cache_info;
1868
cristy3ed852e2009-09-05 21:47:34 +00001869 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001870 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001871 status;
1872
cristy50a10922010-02-15 18:35:25 +00001873 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001874 cpu_throttle = 0,
1875 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001876 time_limit = 0;
1877
cristy1ea34962010-07-01 19:49:21 +00001878 static time_t
cristy208b1002011-08-07 18:51:50 +00001879 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001880
cristyc4f9f132010-03-04 18:50:01 +00001881 status=MagickTrue;
1882 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001883 if (cpu_throttle == 0)
1884 {
1885 char
1886 *limit;
1887
1888 /*
1889 Set CPU throttle in milleseconds.
1890 */
1891 cpu_throttle=MagickResourceInfinity;
1892 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1893 if (limit == (char *) NULL)
1894 limit=GetPolicyValue("throttle");
1895 if (limit != (char *) NULL)
1896 {
1897 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1898 limit=DestroyString(limit);
1899 }
1900 }
1901 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1902 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001903 if (time_limit == 0)
1904 {
cristy6ebe97c2010-07-03 01:17:28 +00001905 /*
1906 Set the exire time in seconds.
1907 */
cristy1ea34962010-07-01 19:49:21 +00001908 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001909 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001910 }
1911 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001912 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001913 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001914 assert(image->cache != (Cache) NULL);
1915 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001916 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001917 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001918 {
cristyceb55ee2010-11-06 16:05:49 +00001919 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001920 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001921 {
cristyceb55ee2010-11-06 16:05:49 +00001922 Image
1923 clone_image;
1924
1925 CacheInfo
1926 *clone_info;
1927
1928 /*
1929 Clone pixel cache.
1930 */
1931 clone_image=(*image);
1932 clone_image.semaphore=AllocateSemaphoreInfo();
1933 clone_image.reference_count=1;
1934 clone_image.cache=ClonePixelCache(cache_info);
1935 clone_info=(CacheInfo *) clone_image.cache;
1936 status=OpenPixelCache(&clone_image,IOMode,exception);
1937 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001938 {
cristy5a7fbfb2010-11-06 16:10:59 +00001939 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001940 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001941 if (status != MagickFalse)
1942 {
cristy979bf772011-08-08 00:04:15 +00001943 if (cache_info->mode == ReadMode)
1944 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001945 destroy=MagickTrue;
1946 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001947 }
1948 }
cristyceb55ee2010-11-06 16:05:49 +00001949 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001950 }
cristyceb55ee2010-11-06 16:05:49 +00001951 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001952 }
cristy4320e0e2009-09-10 15:00:08 +00001953 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001954 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001955 if (status != MagickFalse)
1956 {
1957 /*
1958 Ensure the image matches the pixel cache morphology.
1959 */
1960 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001961 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001962 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001963 {
1964 status=OpenPixelCache(image,IOMode,exception);
1965 cache_info=(CacheInfo *) image->cache;
1966 if (cache_info->type == DiskCache)
1967 (void) ClosePixelCacheOnDisk(cache_info);
1968 }
cristy3ed852e2009-09-05 21:47:34 +00001969 }
cristyf84a1932010-01-03 18:00:18 +00001970 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001971 if (status == MagickFalse)
1972 return((Cache) NULL);
1973 return(image->cache);
1974}
1975
1976/*
1977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1978% %
1979% %
1980% %
cristyce1fe792012-05-16 15:58:37 +00001981+ G e t I m a g e P i x e l C a c h e T y p e %
1982% %
1983% %
1984% %
1985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986%
1987% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1988% DiskCache, MemoryCache, MapCache, or PingCache.
1989%
1990% The format of the GetImagePixelCacheType() method is:
1991%
cristy5bef4cd2012-05-17 18:08:56 +00001992% CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00001993%
1994% A description of each parameter follows:
1995%
1996% o image: the image.
1997%
1998*/
cristy5bef4cd2012-05-17 18:08:56 +00001999MagickExport CacheType GetImagePixelCacheType(const Image *image)
cristyce1fe792012-05-16 15:58:37 +00002000{
cristy238287d2012-05-17 18:16:56 +00002001 CacheInfo
2002 *cache_info;
2003
2004 assert(image != (Image *) NULL);
2005 assert(image->signature == MagickSignature);
2006 assert(image->cache != (Cache) NULL);
2007 cache_info=(CacheInfo *) image->cache;
2008 assert(cache_info->signature == MagickSignature);
2009 return(cache_info->type);
cristyce1fe792012-05-16 15:58:37 +00002010}
2011
2012/*
2013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2014% %
2015% %
2016% %
cristy3ed852e2009-09-05 21:47:34 +00002017% G e t O n e A u t h e n t i c P i x e l %
2018% %
2019% %
2020% %
2021%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2022%
2023% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2024% location. The image background color is returned if an error occurs.
2025%
2026% The format of the GetOneAuthenticPixel() method is:
2027%
cristybb503372010-05-27 20:51:26 +00002028% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002029% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002030%
2031% A description of each parameter follows:
2032%
2033% o image: the image.
2034%
2035% o x,y: These values define the location of the pixel to return.
2036%
2037% o pixel: return a pixel at the specified (x,y) location.
2038%
2039% o exception: return any errors or warnings in this structure.
2040%
2041*/
cristyacbbb7c2010-06-30 18:56:48 +00002042MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002043 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002044{
2045 CacheInfo
2046 *cache_info;
2047
cristy4c08aed2011-07-01 19:47:50 +00002048 register Quantum
2049 *q;
cristy2036f5c2010-09-19 21:18:17 +00002050
cristy2ed42f62011-10-02 19:49:57 +00002051 register ssize_t
2052 i;
2053
cristy3ed852e2009-09-05 21:47:34 +00002054 assert(image != (Image *) NULL);
2055 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002056 assert(image->cache != (Cache) NULL);
2057 cache_info=(CacheInfo *) image->cache;
2058 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002059 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002060 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2061 (GetOneAuthenticPixelFromHandler) NULL)
2062 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2063 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002064 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2065 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002066 {
cristy9e0719b2011-12-29 03:45:45 +00002067 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2068 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2069 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2070 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2071 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002072 return(MagickFalse);
2073 }
2074 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2075 {
2076 PixelChannel
2077 channel;
2078
cristye2a912b2011-12-05 20:02:07 +00002079 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002080 pixel[channel]=q[i];
2081 }
cristy2036f5c2010-09-19 21:18:17 +00002082 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002083}
2084
2085/*
2086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2087% %
2088% %
2089% %
2090+ 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 %
2091% %
2092% %
2093% %
2094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2095%
2096% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2097% location. The image background color is returned if an error occurs.
2098%
2099% The format of the GetOneAuthenticPixelFromCache() method is:
2100%
2101% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002102% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002103% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002104%
2105% A description of each parameter follows:
2106%
2107% o image: the image.
2108%
2109% o x,y: These values define the location of the pixel to return.
2110%
2111% o pixel: return a pixel at the specified (x,y) location.
2112%
2113% o exception: return any errors or warnings in this structure.
2114%
2115*/
2116static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002117 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002118{
cristy098f78c2010-09-23 17:28:44 +00002119 CacheInfo
2120 *cache_info;
2121
2122 const int
2123 id = GetOpenMPThreadId();
2124
cristy4c08aed2011-07-01 19:47:50 +00002125 register Quantum
2126 *q;
cristy3ed852e2009-09-05 21:47:34 +00002127
cristy2ed42f62011-10-02 19:49:57 +00002128 register ssize_t
2129 i;
2130
cristy0158a4b2010-09-20 13:59:45 +00002131 assert(image != (const Image *) NULL);
2132 assert(image->signature == MagickSignature);
2133 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002134 cache_info=(CacheInfo *) image->cache;
2135 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002136 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002137 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002138 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2139 exception);
2140 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002141 {
cristy9e0719b2011-12-29 03:45:45 +00002142 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2143 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2144 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2145 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2146 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002147 return(MagickFalse);
2148 }
2149 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2150 {
2151 PixelChannel
2152 channel;
2153
cristye2a912b2011-12-05 20:02:07 +00002154 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002155 pixel[channel]=q[i];
2156 }
cristy3ed852e2009-09-05 21:47:34 +00002157 return(MagickTrue);
2158}
2159
2160/*
2161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2162% %
2163% %
2164% %
cristy3ed852e2009-09-05 21:47:34 +00002165% G e t O n e V i r t u a l P i x e l %
2166% %
2167% %
2168% %
2169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2170%
2171% GetOneVirtualPixel() returns a single virtual pixel at the specified
2172% (x,y) location. The image background color is returned if an error occurs.
2173% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2174%
2175% The format of the GetOneVirtualPixel() method is:
2176%
cristybb503372010-05-27 20:51:26 +00002177% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002178% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002179%
2180% A description of each parameter follows:
2181%
2182% o image: the image.
2183%
2184% o x,y: These values define the location of the pixel to return.
2185%
2186% o pixel: return a pixel at the specified (x,y) location.
2187%
2188% o exception: return any errors or warnings in this structure.
2189%
2190*/
2191MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002192 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002193{
cristy3ed852e2009-09-05 21:47:34 +00002194 CacheInfo
2195 *cache_info;
2196
cristy0158a4b2010-09-20 13:59:45 +00002197 const int
2198 id = GetOpenMPThreadId();
2199
cristy4c08aed2011-07-01 19:47:50 +00002200 const Quantum
2201 *p;
cristy2036f5c2010-09-19 21:18:17 +00002202
cristy2ed42f62011-10-02 19:49:57 +00002203 register ssize_t
2204 i;
2205
cristy3ed852e2009-09-05 21:47:34 +00002206 assert(image != (const Image *) NULL);
2207 assert(image->signature == MagickSignature);
2208 assert(image->cache != (Cache) NULL);
2209 cache_info=(CacheInfo *) image->cache;
2210 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002211 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002212 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2213 (GetOneVirtualPixelFromHandler) NULL)
2214 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2215 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002216 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002217 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002218 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002219 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002220 {
cristy9e0719b2011-12-29 03:45:45 +00002221 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2222 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2223 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2224 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2225 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002226 return(MagickFalse);
2227 }
2228 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2229 {
2230 PixelChannel
2231 channel;
2232
cristye2a912b2011-12-05 20:02:07 +00002233 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002234 pixel[channel]=p[i];
2235 }
cristy2036f5c2010-09-19 21:18:17 +00002236 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002237}
2238
2239/*
2240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2241% %
2242% %
2243% %
2244+ 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 %
2245% %
2246% %
2247% %
2248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2249%
2250% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2251% specified (x,y) location. The image background color is returned if an
2252% error occurs.
2253%
2254% The format of the GetOneVirtualPixelFromCache() method is:
2255%
2256% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002257% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002258% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002259%
2260% A description of each parameter follows:
2261%
2262% o image: the image.
2263%
2264% o virtual_pixel_method: the virtual pixel method.
2265%
2266% o x,y: These values define the location of the pixel to return.
2267%
2268% o pixel: return a pixel at the specified (x,y) location.
2269%
2270% o exception: return any errors or warnings in this structure.
2271%
2272*/
2273static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002274 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002275 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002276{
cristy0158a4b2010-09-20 13:59:45 +00002277 CacheInfo
2278 *cache_info;
2279
2280 const int
2281 id = GetOpenMPThreadId();
2282
cristy4c08aed2011-07-01 19:47:50 +00002283 const Quantum
2284 *p;
cristy3ed852e2009-09-05 21:47:34 +00002285
cristy2ed42f62011-10-02 19:49:57 +00002286 register ssize_t
2287 i;
2288
cristye7cc7cf2010-09-21 13:26:47 +00002289 assert(image != (const Image *) NULL);
2290 assert(image->signature == MagickSignature);
2291 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002292 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002293 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002294 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002295 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002296 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002297 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002298 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002299 {
cristy9e0719b2011-12-29 03:45:45 +00002300 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2301 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2302 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2303 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2304 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002305 return(MagickFalse);
2306 }
2307 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2308 {
2309 PixelChannel
2310 channel;
2311
cristye2a912b2011-12-05 20:02:07 +00002312 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002313 pixel[channel]=p[i];
2314 }
cristy3ed852e2009-09-05 21:47:34 +00002315 return(MagickTrue);
2316}
2317
2318/*
2319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2320% %
2321% %
2322% %
cristy3aa93752011-12-18 15:54:24 +00002323% G e t O n e V i r t u a l P i x e l I n f o %
2324% %
2325% %
2326% %
2327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2328%
2329% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2330% location. The image background color is returned if an error occurs. If
2331% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2332%
2333% The format of the GetOneVirtualPixelInfo() method is:
2334%
2335% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2336% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2337% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2338%
2339% A description of each parameter follows:
2340%
2341% o image: the image.
2342%
2343% o virtual_pixel_method: the virtual pixel method.
2344%
2345% o x,y: these values define the location of the pixel to return.
2346%
2347% o pixel: return a pixel at the specified (x,y) location.
2348%
2349% o exception: return any errors or warnings in this structure.
2350%
2351*/
2352MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2353 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2354 PixelInfo *pixel,ExceptionInfo *exception)
2355{
2356 CacheInfo
2357 *cache_info;
2358
2359 const int
2360 id = GetOpenMPThreadId();
2361
2362 register const Quantum
2363 *p;
2364
2365 assert(image != (const Image *) NULL);
2366 assert(image->signature == MagickSignature);
2367 assert(image->cache != (Cache) NULL);
2368 cache_info=(CacheInfo *) image->cache;
2369 assert(cache_info->signature == MagickSignature);
2370 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002371 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002372 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2373 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002374 if (p == (const Quantum *) NULL)
2375 return(MagickFalse);
2376 GetPixelInfoPixel(image,p,pixel);
2377 return(MagickTrue);
2378}
2379
2380/*
2381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2382% %
2383% %
2384% %
cristy3ed852e2009-09-05 21:47:34 +00002385+ G e t P i x e l C a c h e C o l o r s p a c e %
2386% %
2387% %
2388% %
2389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2390%
2391% GetPixelCacheColorspace() returns the class type of the pixel cache.
2392%
2393% The format of the GetPixelCacheColorspace() method is:
2394%
2395% Colorspace GetPixelCacheColorspace(Cache cache)
2396%
2397% A description of each parameter follows:
2398%
2399% o cache: the pixel cache.
2400%
2401*/
cristya6577ff2011-09-02 19:54:26 +00002402MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002403{
2404 CacheInfo
2405 *cache_info;
2406
2407 assert(cache != (Cache) NULL);
2408 cache_info=(CacheInfo *) cache;
2409 assert(cache_info->signature == MagickSignature);
2410 if (cache_info->debug != MagickFalse)
2411 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2412 cache_info->filename);
2413 return(cache_info->colorspace);
2414}
2415
2416/*
2417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2418% %
2419% %
2420% %
2421+ G e t P i x e l C a c h e M e t h o d s %
2422% %
2423% %
2424% %
2425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2426%
2427% GetPixelCacheMethods() initializes the CacheMethods structure.
2428%
2429% The format of the GetPixelCacheMethods() method is:
2430%
2431% void GetPixelCacheMethods(CacheMethods *cache_methods)
2432%
2433% A description of each parameter follows:
2434%
2435% o cache_methods: Specifies a pointer to a CacheMethods structure.
2436%
2437*/
cristya6577ff2011-09-02 19:54:26 +00002438MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002439{
2440 assert(cache_methods != (CacheMethods *) NULL);
2441 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2442 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2443 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002444 cache_methods->get_virtual_metacontent_from_handler=
2445 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002446 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2447 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002448 cache_methods->get_authentic_metacontent_from_handler=
2449 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002450 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2451 cache_methods->get_one_authentic_pixel_from_handler=
2452 GetOneAuthenticPixelFromCache;
2453 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2454 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2455 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2456}
2457
2458/*
2459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2460% %
2461% %
2462% %
2463+ G e t P i x e l C a c h e N e x u s E x t e n t %
2464% %
2465% %
2466% %
2467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2468%
cristy4c08aed2011-07-01 19:47:50 +00002469% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2470% corresponding with the last call to SetPixelCacheNexusPixels() or
2471% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002472%
2473% The format of the GetPixelCacheNexusExtent() method is:
2474%
2475% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2476% NexusInfo *nexus_info)
2477%
2478% A description of each parameter follows:
2479%
2480% o nexus_info: the nexus info.
2481%
2482*/
cristya6577ff2011-09-02 19:54:26 +00002483MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002484 NexusInfo *nexus_info)
2485{
2486 CacheInfo
2487 *cache_info;
2488
2489 MagickSizeType
2490 extent;
2491
cristy9f027d12011-09-21 01:17:17 +00002492 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002493 cache_info=(CacheInfo *) cache;
2494 assert(cache_info->signature == MagickSignature);
2495 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2496 if (extent == 0)
2497 return((MagickSizeType) cache_info->columns*cache_info->rows);
2498 return(extent);
2499}
2500
2501/*
2502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2503% %
2504% %
2505% %
cristy4c08aed2011-07-01 19:47:50 +00002506+ 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 +00002507% %
2508% %
2509% %
2510%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2511%
cristy4c08aed2011-07-01 19:47:50 +00002512% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2513% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002514%
cristy4c08aed2011-07-01 19:47:50 +00002515% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002516%
cristy4c08aed2011-07-01 19:47:50 +00002517% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002518% NexusInfo *nexus_info)
2519%
2520% A description of each parameter follows:
2521%
2522% o cache: the pixel cache.
2523%
cristy4c08aed2011-07-01 19:47:50 +00002524% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002525%
2526*/
cristya6577ff2011-09-02 19:54:26 +00002527MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002528 NexusInfo *nexus_info)
2529{
2530 CacheInfo
2531 *cache_info;
2532
cristy9f027d12011-09-21 01:17:17 +00002533 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002534 cache_info=(CacheInfo *) cache;
2535 assert(cache_info->signature == MagickSignature);
2536 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002537 return((void *) NULL);
2538 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002539}
2540
2541/*
2542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543% %
2544% %
2545% %
2546+ G e t P i x e l C a c h e N e x u s P i x e l s %
2547% %
2548% %
2549% %
2550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2551%
2552% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2553% cache nexus.
2554%
2555% The format of the GetPixelCacheNexusPixels() method is:
2556%
cristy4c08aed2011-07-01 19:47:50 +00002557% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002558% NexusInfo *nexus_info)
2559%
2560% A description of each parameter follows:
2561%
2562% o cache: the pixel cache.
2563%
2564% o nexus_info: the cache nexus to return the pixels.
2565%
2566*/
cristya6577ff2011-09-02 19:54:26 +00002567MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002568 NexusInfo *nexus_info)
2569{
2570 CacheInfo
2571 *cache_info;
2572
cristy9f027d12011-09-21 01:17:17 +00002573 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002574 cache_info=(CacheInfo *) cache;
2575 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002576 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002577 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002578 return(nexus_info->pixels);
2579}
2580
2581/*
2582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2583% %
2584% %
2585% %
cristy056ba772010-01-02 23:33:54 +00002586+ G e t P i x e l C a c h e P i x e l s %
2587% %
2588% %
2589% %
2590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591%
2592% GetPixelCachePixels() returns the pixels associated with the specified image.
2593%
2594% The format of the GetPixelCachePixels() method is:
2595%
cristyf84a1932010-01-03 18:00:18 +00002596% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2597% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002598%
2599% A description of each parameter follows:
2600%
2601% o image: the image.
2602%
2603% o length: the pixel cache length.
2604%
cristyf84a1932010-01-03 18:00:18 +00002605% o exception: return any errors or warnings in this structure.
2606%
cristy056ba772010-01-02 23:33:54 +00002607*/
cristyd1dd6e42011-09-04 01:46:08 +00002608MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002609 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002610{
2611 CacheInfo
2612 *cache_info;
2613
2614 assert(image != (const Image *) NULL);
2615 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002616 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002617 assert(length != (MagickSizeType *) NULL);
2618 assert(exception != (ExceptionInfo *) NULL);
2619 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002620 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002621 assert(cache_info->signature == MagickSignature);
2622 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002623 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002624 return((void *) NULL);
2625 *length=cache_info->length;
2626 return((void *) cache_info->pixels);
2627}
2628
2629/*
2630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2631% %
2632% %
2633% %
cristyb32b90a2009-09-07 21:45:48 +00002634+ 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 +00002635% %
2636% %
2637% %
2638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2639%
2640% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2641%
2642% The format of the GetPixelCacheStorageClass() method is:
2643%
2644% ClassType GetPixelCacheStorageClass(Cache cache)
2645%
2646% A description of each parameter follows:
2647%
2648% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2649%
2650% o cache: the pixel cache.
2651%
2652*/
cristya6577ff2011-09-02 19:54:26 +00002653MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002654{
2655 CacheInfo
2656 *cache_info;
2657
2658 assert(cache != (Cache) NULL);
2659 cache_info=(CacheInfo *) cache;
2660 assert(cache_info->signature == MagickSignature);
2661 if (cache_info->debug != MagickFalse)
2662 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2663 cache_info->filename);
2664 return(cache_info->storage_class);
2665}
2666
2667/*
2668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2669% %
2670% %
2671% %
cristyb32b90a2009-09-07 21:45:48 +00002672+ G e t P i x e l C a c h e T i l e S i z e %
2673% %
2674% %
2675% %
2676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2677%
2678% GetPixelCacheTileSize() returns the pixel cache tile size.
2679%
2680% The format of the GetPixelCacheTileSize() method is:
2681%
cristybb503372010-05-27 20:51:26 +00002682% void GetPixelCacheTileSize(const Image *image,size_t *width,
2683% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002684%
2685% A description of each parameter follows:
2686%
2687% o image: the image.
2688%
2689% o width: the optimize cache tile width in pixels.
2690%
2691% o height: the optimize cache tile height in pixels.
2692%
2693*/
cristya6577ff2011-09-02 19:54:26 +00002694MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002695 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002696{
cristy4c08aed2011-07-01 19:47:50 +00002697 CacheInfo
2698 *cache_info;
2699
cristyb32b90a2009-09-07 21:45:48 +00002700 assert(image != (Image *) NULL);
2701 assert(image->signature == MagickSignature);
2702 if (image->debug != MagickFalse)
2703 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002704 cache_info=(CacheInfo *) image->cache;
2705 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002706 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristy238287d2012-05-17 18:16:56 +00002707 if (GetImagePixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002708 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002709 *height=(*width);
2710}
2711
2712/*
2713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714% %
2715% %
2716% %
cristy3ed852e2009-09-05 21:47:34 +00002717+ 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 %
2718% %
2719% %
2720% %
2721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722%
2723% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2724% pixel cache. A virtual pixel is any pixel access that is outside the
2725% boundaries of the image cache.
2726%
2727% The format of the GetPixelCacheVirtualMethod() method is:
2728%
2729% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2730%
2731% A description of each parameter follows:
2732%
2733% o image: the image.
2734%
2735*/
cristyd1dd6e42011-09-04 01:46:08 +00002736MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002737{
2738 CacheInfo
2739 *cache_info;
2740
2741 assert(image != (Image *) NULL);
2742 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002743 assert(image->cache != (Cache) NULL);
2744 cache_info=(CacheInfo *) image->cache;
2745 assert(cache_info->signature == MagickSignature);
2746 return(cache_info->virtual_pixel_method);
2747}
2748
2749/*
2750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2751% %
2752% %
2753% %
cristy4c08aed2011-07-01 19:47:50 +00002754+ 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 +00002755% %
2756% %
2757% %
2758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2759%
cristy4c08aed2011-07-01 19:47:50 +00002760% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2761% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002762%
cristy4c08aed2011-07-01 19:47:50 +00002763% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002764%
cristy4c08aed2011-07-01 19:47:50 +00002765% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002766%
2767% A description of each parameter follows:
2768%
2769% o image: the image.
2770%
2771*/
cristy4c08aed2011-07-01 19:47:50 +00002772static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002773{
2774 CacheInfo
2775 *cache_info;
2776
cristy5c9e6f22010-09-17 17:31:01 +00002777 const int
2778 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002779
cristy4c08aed2011-07-01 19:47:50 +00002780 const void
2781 *metacontent;
2782
cristye7cc7cf2010-09-21 13:26:47 +00002783 assert(image != (const Image *) NULL);
2784 assert(image->signature == MagickSignature);
2785 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002786 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002787 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002788 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002789 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2790 cache_info->nexus_info[id]);
2791 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002792}
2793
2794/*
2795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796% %
2797% %
2798% %
cristy4c08aed2011-07-01 19:47:50 +00002799+ 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 +00002800% %
2801% %
2802% %
2803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804%
cristy4c08aed2011-07-01 19:47:50 +00002805% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2806% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002807%
cristy4c08aed2011-07-01 19:47:50 +00002808% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002809%
cristy4c08aed2011-07-01 19:47:50 +00002810% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002811% NexusInfo *nexus_info)
2812%
2813% A description of each parameter follows:
2814%
2815% o cache: the pixel cache.
2816%
cristy4c08aed2011-07-01 19:47:50 +00002817% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002818%
2819*/
cristya6577ff2011-09-02 19:54:26 +00002820MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002821 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002822{
2823 CacheInfo
2824 *cache_info;
2825
cristye7cc7cf2010-09-21 13:26:47 +00002826 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002827 cache_info=(CacheInfo *) cache;
2828 assert(cache_info->signature == MagickSignature);
2829 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002830 return((void *) NULL);
2831 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002832}
2833
2834/*
2835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2836% %
2837% %
2838% %
cristy4c08aed2011-07-01 19:47:50 +00002839% 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 +00002840% %
2841% %
2842% %
2843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2844%
cristy4c08aed2011-07-01 19:47:50 +00002845% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2846% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2847% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002848%
cristy4c08aed2011-07-01 19:47:50 +00002849% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002850%
cristy4c08aed2011-07-01 19:47:50 +00002851% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002852%
2853% A description of each parameter follows:
2854%
2855% o image: the image.
2856%
2857*/
cristy4c08aed2011-07-01 19:47:50 +00002858MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002859{
2860 CacheInfo
2861 *cache_info;
2862
cristy2036f5c2010-09-19 21:18:17 +00002863 const int
2864 id = GetOpenMPThreadId();
2865
cristy4c08aed2011-07-01 19:47:50 +00002866 const void
2867 *metacontent;
2868
cristy3ed852e2009-09-05 21:47:34 +00002869 assert(image != (const Image *) NULL);
2870 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002871 assert(image->cache != (Cache) NULL);
2872 cache_info=(CacheInfo *) image->cache;
2873 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002874 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
cristyadf82722012-05-11 17:34:16 +00002875 if (metacontent != (void *) NULL)
cristya26c6622012-02-14 14:00:20 +00002876 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002877 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002878 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2879 cache_info->nexus_info[id]);
2880 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002881}
2882
2883/*
2884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885% %
2886% %
2887% %
2888+ 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 %
2889% %
2890% %
2891% %
2892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2893%
2894% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2895% pixel cache as defined by the geometry parameters. A pointer to the pixels
2896% is returned if the pixels are transferred, otherwise a NULL is returned.
2897%
2898% The format of the GetVirtualPixelsFromNexus() method is:
2899%
cristy4c08aed2011-07-01 19:47:50 +00002900% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002901% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002902% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2903% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002904%
2905% A description of each parameter follows:
2906%
2907% o image: the image.
2908%
2909% o virtual_pixel_method: the virtual pixel method.
2910%
2911% o x,y,columns,rows: These values define the perimeter of a region of
2912% pixels.
2913%
2914% o nexus_info: the cache nexus to acquire.
2915%
2916% o exception: return any errors or warnings in this structure.
2917%
2918*/
2919
cristybb503372010-05-27 20:51:26 +00002920static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002921 DitherMatrix[64] =
2922 {
2923 0, 48, 12, 60, 3, 51, 15, 63,
2924 32, 16, 44, 28, 35, 19, 47, 31,
2925 8, 56, 4, 52, 11, 59, 7, 55,
2926 40, 24, 36, 20, 43, 27, 39, 23,
2927 2, 50, 14, 62, 1, 49, 13, 61,
2928 34, 18, 46, 30, 33, 17, 45, 29,
2929 10, 58, 6, 54, 9, 57, 5, 53,
2930 42, 26, 38, 22, 41, 25, 37, 21
2931 };
2932
cristybb503372010-05-27 20:51:26 +00002933static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002934{
cristybb503372010-05-27 20:51:26 +00002935 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002936 index;
2937
2938 index=x+DitherMatrix[x & 0x07]-32L;
2939 if (index < 0L)
2940 return(0L);
cristybb503372010-05-27 20:51:26 +00002941 if (index >= (ssize_t) columns)
2942 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002943 return(index);
2944}
2945
cristybb503372010-05-27 20:51:26 +00002946static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002947{
cristybb503372010-05-27 20:51:26 +00002948 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002949 index;
2950
2951 index=y+DitherMatrix[y & 0x07]-32L;
2952 if (index < 0L)
2953 return(0L);
cristybb503372010-05-27 20:51:26 +00002954 if (index >= (ssize_t) rows)
2955 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002956 return(index);
2957}
2958
cristybb503372010-05-27 20:51:26 +00002959static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002960{
2961 if (x < 0L)
2962 return(0L);
cristybb503372010-05-27 20:51:26 +00002963 if (x >= (ssize_t) columns)
2964 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002965 return(x);
2966}
2967
cristybb503372010-05-27 20:51:26 +00002968static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002969{
2970 if (y < 0L)
2971 return(0L);
cristybb503372010-05-27 20:51:26 +00002972 if (y >= (ssize_t) rows)
2973 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002974 return(y);
2975}
2976
cristybb503372010-05-27 20:51:26 +00002977static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002978{
cristybb503372010-05-27 20:51:26 +00002979 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002980}
2981
cristybb503372010-05-27 20:51:26 +00002982static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002983{
cristybb503372010-05-27 20:51:26 +00002984 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002985}
2986
cristybb503372010-05-27 20:51:26 +00002987static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2988 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002989{
2990 MagickModulo
2991 modulo;
2992
cristy6162bb42011-07-18 11:34:09 +00002993 /*
2994 Compute the remainder of dividing offset by extent. It returns not only
2995 the quotient (tile the offset falls in) but also the positive remainer
2996 within that tile such that 0 <= remainder < extent. This method is
2997 essentially a ldiv() using a floored modulo division rather than the
2998 normal default truncated modulo division.
2999 */
cristybb503372010-05-27 20:51:26 +00003000 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003001 if (offset < 0L)
3002 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003003 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003004 return(modulo);
3005}
3006
cristya6577ff2011-09-02 19:54:26 +00003007MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003008 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3009 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003010 ExceptionInfo *exception)
3011{
3012 CacheInfo
3013 *cache_info;
3014
3015 MagickOffsetType
3016 offset;
3017
3018 MagickSizeType
3019 length,
3020 number_pixels;
3021
3022 NexusInfo
3023 **virtual_nexus;
3024
cristy4c08aed2011-07-01 19:47:50 +00003025 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003026 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003027 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003028
3029 RectangleInfo
3030 region;
3031
cristy4c08aed2011-07-01 19:47:50 +00003032 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003033 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003034
cristy4c08aed2011-07-01 19:47:50 +00003035 register const void
3036 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003037
cristy4c08aed2011-07-01 19:47:50 +00003038 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003039 *restrict q;
3040
cristybb503372010-05-27 20:51:26 +00003041 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003042 i,
3043 u;
cristy3ed852e2009-09-05 21:47:34 +00003044
cristy4c08aed2011-07-01 19:47:50 +00003045 register unsigned char
3046 *restrict s;
3047
cristy105ba3c2011-07-18 02:28:38 +00003048 ssize_t
3049 v;
3050
cristy4c08aed2011-07-01 19:47:50 +00003051 void
cristy105ba3c2011-07-18 02:28:38 +00003052 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003053
cristy3ed852e2009-09-05 21:47:34 +00003054 /*
3055 Acquire pixels.
3056 */
cristye7cc7cf2010-09-21 13:26:47 +00003057 assert(image != (const Image *) NULL);
3058 assert(image->signature == MagickSignature);
3059 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003060 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003061 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003062 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003063 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003064 region.x=x;
3065 region.y=y;
3066 region.width=columns;
3067 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003068 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003069 if (pixels == (Quantum *) NULL)
3070 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003071 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003072 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3073 nexus_info->region.x;
3074 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3075 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003076 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3077 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003078 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3079 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003080 {
3081 MagickBooleanType
3082 status;
3083
3084 /*
3085 Pixel request is inside cache extents.
3086 */
cristy4c08aed2011-07-01 19:47:50 +00003087 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003088 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003089 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3090 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003091 return((const Quantum *) NULL);
3092 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003093 {
cristy4c08aed2011-07-01 19:47:50 +00003094 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003095 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003096 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003097 }
cristyacd2ed22011-08-30 01:44:23 +00003098 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003099 }
3100 /*
3101 Pixel request is outside cache extents.
3102 */
cristy4c08aed2011-07-01 19:47:50 +00003103 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003104 virtual_nexus=AcquirePixelCacheNexus(1);
3105 if (virtual_nexus == (NexusInfo **) NULL)
3106 {
cristy4c08aed2011-07-01 19:47:50 +00003107 if (virtual_nexus != (NexusInfo **) NULL)
3108 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003109 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003110 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003111 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003112 }
cristy105ba3c2011-07-18 02:28:38 +00003113 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3114 sizeof(*virtual_pixel));
3115 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003116 switch (virtual_pixel_method)
3117 {
cristy4c08aed2011-07-01 19:47:50 +00003118 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003119 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003121 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003122 case MaskVirtualPixelMethod:
3123 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003124 case EdgeVirtualPixelMethod:
3125 case CheckerTileVirtualPixelMethod:
3126 case HorizontalTileVirtualPixelMethod:
3127 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003128 {
cristy4c08aed2011-07-01 19:47:50 +00003129 if (cache_info->metacontent_extent != 0)
3130 {
cristy6162bb42011-07-18 11:34:09 +00003131 /*
3132 Acquire a metacontent buffer.
3133 */
cristya64b85d2011-09-14 01:02:31 +00003134 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003135 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003136 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003137 {
cristy4c08aed2011-07-01 19:47:50 +00003138 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3139 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003140 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003141 return((const Quantum *) NULL);
3142 }
cristy105ba3c2011-07-18 02:28:38 +00003143 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003144 cache_info->metacontent_extent);
3145 }
3146 switch (virtual_pixel_method)
3147 {
3148 case BlackVirtualPixelMethod:
3149 {
cristy30301712011-07-18 15:06:51 +00003150 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3151 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003152 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3153 break;
3154 }
3155 case GrayVirtualPixelMethod:
3156 {
cristy30301712011-07-18 15:06:51 +00003157 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003158 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3159 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003160 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3161 break;
3162 }
3163 case TransparentVirtualPixelMethod:
3164 {
cristy30301712011-07-18 15:06:51 +00003165 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3166 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003167 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3168 break;
3169 }
3170 case MaskVirtualPixelMethod:
3171 case WhiteVirtualPixelMethod:
3172 {
cristy30301712011-07-18 15:06:51 +00003173 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3174 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003175 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3176 break;
3177 }
3178 default:
3179 {
cristy9e0719b2011-12-29 03:45:45 +00003180 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3181 virtual_pixel);
3182 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3183 virtual_pixel);
3184 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3185 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003186 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3187 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003188 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3189 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003190 break;
3191 }
3192 }
cristy3ed852e2009-09-05 21:47:34 +00003193 break;
3194 }
3195 default:
cristy3ed852e2009-09-05 21:47:34 +00003196 break;
cristy3ed852e2009-09-05 21:47:34 +00003197 }
cristybb503372010-05-27 20:51:26 +00003198 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003199 {
cristybb503372010-05-27 20:51:26 +00003200 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003201 {
3202 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003203 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003204 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3205 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003206 {
3207 MagickModulo
3208 x_modulo,
3209 y_modulo;
3210
3211 /*
3212 Transfer a single pixel.
3213 */
3214 length=(MagickSizeType) 1;
3215 switch (virtual_pixel_method)
3216 {
cristy3ed852e2009-09-05 21:47:34 +00003217 default:
3218 {
3219 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003220 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003221 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003222 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003223 break;
3224 }
3225 case RandomVirtualPixelMethod:
3226 {
3227 if (cache_info->random_info == (RandomInfo *) NULL)
3228 cache_info->random_info=AcquireRandomInfo();
3229 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003230 RandomX(cache_info->random_info,cache_info->columns),
3231 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003232 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003233 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003234 break;
3235 }
3236 case DitherVirtualPixelMethod:
3237 {
3238 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003239 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003240 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003241 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003242 break;
3243 }
3244 case TileVirtualPixelMethod:
3245 {
3246 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3247 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3248 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003249 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003250 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 MirrorVirtualPixelMethod:
3255 {
3256 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3257 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003258 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003259 x_modulo.remainder-1L;
3260 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3261 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003262 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003263 y_modulo.remainder-1L;
3264 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003265 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003266 exception);
cristy4c08aed2011-07-01 19:47:50 +00003267 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003268 break;
3269 }
3270 case HorizontalTileEdgeVirtualPixelMethod:
3271 {
3272 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3273 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003274 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003275 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003276 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003277 break;
3278 }
3279 case VerticalTileEdgeVirtualPixelMethod:
3280 {
3281 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3282 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003283 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003284 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003285 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3286 break;
3287 }
3288 case BackgroundVirtualPixelMethod:
3289 case BlackVirtualPixelMethod:
3290 case GrayVirtualPixelMethod:
3291 case TransparentVirtualPixelMethod:
3292 case MaskVirtualPixelMethod:
3293 case WhiteVirtualPixelMethod:
3294 {
3295 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003296 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003297 break;
3298 }
3299 case EdgeVirtualPixelMethod:
3300 case CheckerTileVirtualPixelMethod:
3301 {
3302 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3303 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3304 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3305 {
3306 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003307 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003308 break;
3309 }
3310 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3311 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3312 exception);
3313 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3314 break;
3315 }
3316 case HorizontalTileVirtualPixelMethod:
3317 {
3318 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3319 {
3320 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003321 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003322 break;
3323 }
3324 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3325 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3326 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3327 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3328 exception);
3329 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3330 break;
3331 }
3332 case VerticalTileVirtualPixelMethod:
3333 {
3334 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3335 {
3336 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003337 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003338 break;
3339 }
3340 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3341 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3342 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3343 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3344 exception);
3345 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003346 break;
3347 }
3348 }
cristy4c08aed2011-07-01 19:47:50 +00003349 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003350 break;
cristyed231572011-07-14 02:18:59 +00003351 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003352 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003353 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003354 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003355 {
3356 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3357 s+=cache_info->metacontent_extent;
3358 }
cristy3ed852e2009-09-05 21:47:34 +00003359 continue;
3360 }
3361 /*
3362 Transfer a run of pixels.
3363 */
cristy4c08aed2011-07-01 19:47:50 +00003364 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3365 length,1UL,*virtual_nexus,exception);
3366 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003367 break;
cristy4c08aed2011-07-01 19:47:50 +00003368 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003369 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3370 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003371 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003372 {
cristy4c08aed2011-07-01 19:47:50 +00003373 (void) memcpy(s,r,(size_t) length);
3374 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003375 }
3376 }
3377 }
cristy4c08aed2011-07-01 19:47:50 +00003378 /*
3379 Free resources.
3380 */
cristy105ba3c2011-07-18 02:28:38 +00003381 if (virtual_metacontent != (void *) NULL)
3382 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003383 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3384 return(pixels);
3385}
3386
3387/*
3388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3389% %
3390% %
3391% %
3392+ G e t V i r t u a l P i x e l C a c h e %
3393% %
3394% %
3395% %
3396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3397%
3398% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3399% cache as defined by the geometry parameters. A pointer to the pixels
3400% is returned if the pixels are transferred, otherwise a NULL is returned.
3401%
3402% The format of the GetVirtualPixelCache() method is:
3403%
cristy4c08aed2011-07-01 19:47:50 +00003404% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003405% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3406% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003407% ExceptionInfo *exception)
3408%
3409% A description of each parameter follows:
3410%
3411% o image: the image.
3412%
3413% o virtual_pixel_method: the virtual pixel method.
3414%
3415% o x,y,columns,rows: These values define the perimeter of a region of
3416% pixels.
3417%
3418% o exception: return any errors or warnings in this structure.
3419%
3420*/
cristy4c08aed2011-07-01 19:47:50 +00003421static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003422 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3423 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003424{
3425 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003426 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003427
cristy5c9e6f22010-09-17 17:31:01 +00003428 const int
3429 id = GetOpenMPThreadId();
3430
cristy4c08aed2011-07-01 19:47:50 +00003431 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003432 *p;
cristy4c08aed2011-07-01 19:47:50 +00003433
cristye7cc7cf2010-09-21 13:26:47 +00003434 assert(image != (const Image *) NULL);
3435 assert(image->signature == MagickSignature);
3436 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003437 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003438 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003439 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003440 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003441 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003442 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003443}
3444
3445/*
3446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3447% %
3448% %
3449% %
3450% G e t V i r t u a l P i x e l Q u e u e %
3451% %
3452% %
3453% %
3454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3455%
cristy4c08aed2011-07-01 19:47:50 +00003456% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3457% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003458%
3459% The format of the GetVirtualPixelQueue() method is:
3460%
cristy4c08aed2011-07-01 19:47:50 +00003461% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003462%
3463% A description of each parameter follows:
3464%
3465% o image: the image.
3466%
3467*/
cristy4c08aed2011-07-01 19:47:50 +00003468MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003469{
3470 CacheInfo
3471 *cache_info;
3472
cristy2036f5c2010-09-19 21:18:17 +00003473 const int
3474 id = GetOpenMPThreadId();
3475
cristy3ed852e2009-09-05 21:47:34 +00003476 assert(image != (const Image *) NULL);
3477 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003478 assert(image->cache != (Cache) NULL);
3479 cache_info=(CacheInfo *) image->cache;
3480 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003481 if (cache_info->methods.get_virtual_pixels_handler !=
3482 (GetVirtualPixelsHandler) NULL)
3483 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003484 assert(id < (int) cache_info->number_threads);
3485 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003486}
3487
3488/*
3489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3490% %
3491% %
3492% %
3493% G e t V i r t u a l P i x e l s %
3494% %
3495% %
3496% %
3497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3498%
3499% GetVirtualPixels() returns an immutable pixel region. If the
3500% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003501% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003502% copy of the pixels or it may point to the original pixels in memory.
3503% Performance is maximized if the selected region is part of one row, or one
3504% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003505% (without a copy) if the image is in memory, or in a memory-mapped file. The
3506% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003507%
3508% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003509% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3510% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3511% access the meta-content (of type void) corresponding to the the
3512% region.
cristy3ed852e2009-09-05 21:47:34 +00003513%
3514% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3515%
3516% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3517% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3518% GetCacheViewAuthenticPixels() instead.
3519%
3520% The format of the GetVirtualPixels() method is:
3521%
cristy4c08aed2011-07-01 19:47:50 +00003522% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003523% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003524% ExceptionInfo *exception)
3525%
3526% A description of each parameter follows:
3527%
3528% o image: the image.
3529%
3530% o x,y,columns,rows: These values define the perimeter of a region of
3531% pixels.
3532%
3533% o exception: return any errors or warnings in this structure.
3534%
3535*/
cristy4c08aed2011-07-01 19:47:50 +00003536MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003537 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3538 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003539{
3540 CacheInfo
3541 *cache_info;
3542
cristy2036f5c2010-09-19 21:18:17 +00003543 const int
3544 id = GetOpenMPThreadId();
3545
cristy4c08aed2011-07-01 19:47:50 +00003546 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003547 *p;
cristy4c08aed2011-07-01 19:47:50 +00003548
cristy3ed852e2009-09-05 21:47:34 +00003549 assert(image != (const Image *) NULL);
3550 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003551 assert(image->cache != (Cache) NULL);
3552 cache_info=(CacheInfo *) image->cache;
3553 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003554 if (cache_info->methods.get_virtual_pixel_handler !=
3555 (GetVirtualPixelHandler) NULL)
3556 return(cache_info->methods.get_virtual_pixel_handler(image,
3557 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003558 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003559 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003560 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003561 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003562}
3563
3564/*
3565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3566% %
3567% %
3568% %
3569+ 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 %
3570% %
3571% %
3572% %
3573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3574%
cristy4c08aed2011-07-01 19:47:50 +00003575% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3576% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003577%
3578% The format of the GetVirtualPixelsCache() method is:
3579%
cristy4c08aed2011-07-01 19:47:50 +00003580% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003581%
3582% A description of each parameter follows:
3583%
3584% o image: the image.
3585%
3586*/
cristy4c08aed2011-07-01 19:47:50 +00003587static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003588{
3589 CacheInfo
3590 *cache_info;
3591
cristy5c9e6f22010-09-17 17:31:01 +00003592 const int
3593 id = GetOpenMPThreadId();
3594
cristye7cc7cf2010-09-21 13:26:47 +00003595 assert(image != (const Image *) NULL);
3596 assert(image->signature == MagickSignature);
3597 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003598 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003599 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003600 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003601 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003602}
3603
3604/*
3605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3606% %
3607% %
3608% %
3609+ G e t V i r t u a l P i x e l s N e x u s %
3610% %
3611% %
3612% %
3613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614%
3615% GetVirtualPixelsNexus() returns the pixels associated with the specified
3616% cache nexus.
3617%
3618% The format of the GetVirtualPixelsNexus() method is:
3619%
cristy4c08aed2011-07-01 19:47:50 +00003620% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003621% NexusInfo *nexus_info)
3622%
3623% A description of each parameter follows:
3624%
3625% o cache: the pixel cache.
3626%
3627% o nexus_info: the cache nexus to return the colormap pixels.
3628%
3629*/
cristya6577ff2011-09-02 19:54:26 +00003630MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003631 NexusInfo *nexus_info)
3632{
3633 CacheInfo
3634 *cache_info;
3635
cristye7cc7cf2010-09-21 13:26:47 +00003636 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003637 cache_info=(CacheInfo *) cache;
3638 assert(cache_info->signature == MagickSignature);
3639 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003640 return((Quantum *) NULL);
3641 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003642}
3643
3644/*
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646% %
3647% %
3648% %
cristy3ed852e2009-09-05 21:47:34 +00003649+ O p e n P i x e l C a c h e %
3650% %
3651% %
3652% %
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654%
3655% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3656% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003657% metacontent, and memory mapping the cache if it is disk based. The cache
3658% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003659%
3660% The format of the OpenPixelCache() method is:
3661%
3662% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3663% ExceptionInfo *exception)
3664%
3665% A description of each parameter follows:
3666%
3667% o image: the image.
3668%
3669% o mode: ReadMode, WriteMode, or IOMode.
3670%
3671% o exception: return any errors or warnings in this structure.
3672%
3673*/
3674
cristyd43a46b2010-01-21 02:13:41 +00003675static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003676{
3677 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003678 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003679 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003680 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003681 {
3682 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003683 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003684 cache_info->length);
3685 }
3686}
3687
3688static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3689{
3690 CacheInfo
3691 *cache_info;
3692
3693 MagickOffsetType
3694 count,
3695 extent,
3696 offset;
3697
3698 cache_info=(CacheInfo *) image->cache;
3699 if (image->debug != MagickFalse)
3700 {
3701 char
3702 format[MaxTextExtent],
3703 message[MaxTextExtent];
3704
cristyb9080c92009-12-01 20:13:26 +00003705 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003706 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003707 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003708 cache_info->cache_filename,cache_info->file,format);
3709 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3710 }
3711 if (length != (MagickSizeType) ((MagickOffsetType) length))
3712 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003713 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003714 if (extent < 0)
3715 return(MagickFalse);
3716 if ((MagickSizeType) extent >= length)
3717 return(MagickTrue);
3718 offset=(MagickOffsetType) length-1;
3719 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3720 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3721}
3722
3723static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3724 ExceptionInfo *exception)
3725{
cristy3ed852e2009-09-05 21:47:34 +00003726 CacheInfo
3727 *cache_info,
3728 source_info;
3729
cristyf3a6a9d2010-11-07 21:02:56 +00003730 char
3731 format[MaxTextExtent],
3732 message[MaxTextExtent];
3733
cristy4c08aed2011-07-01 19:47:50 +00003734 MagickBooleanType
3735 status;
3736
cristy3ed852e2009-09-05 21:47:34 +00003737 MagickSizeType
3738 length,
3739 number_pixels;
3740
cristy3ed852e2009-09-05 21:47:34 +00003741 size_t
cristye076a6e2010-08-15 19:59:43 +00003742 columns,
cristy3ed852e2009-09-05 21:47:34 +00003743 packet_size;
3744
cristye7cc7cf2010-09-21 13:26:47 +00003745 assert(image != (const Image *) NULL);
3746 assert(image->signature == MagickSignature);
3747 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003748 if (image->debug != MagickFalse)
3749 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3750 if ((image->columns == 0) || (image->rows == 0))
3751 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3752 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003753 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003754 source_info=(*cache_info);
3755 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003756 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003757 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003758 cache_info->storage_class=image->storage_class;
3759 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003760 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003761 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003762 cache_info->rows=image->rows;
3763 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003764 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003765 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003766 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3767 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003768 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003769 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003770 if (image->ping != MagickFalse)
3771 {
cristy73724512010-04-12 14:43:14 +00003772 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003773 cache_info->pixels=(Quantum *) NULL;
3774 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003775 cache_info->length=0;
3776 return(MagickTrue);
3777 }
cristy3ed852e2009-09-05 21:47:34 +00003778 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003779 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003780 if (image->metacontent_extent != 0)
3781 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003782 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003783 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003784 if (cache_info->columns != columns)
3785 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3786 image->filename);
3787 cache_info->length=length;
3788 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003789 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003790 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003791 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3792 {
3793 status=AcquireMagickResource(MemoryResource,cache_info->length);
3794 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3795 (cache_info->type == MemoryCache))
3796 {
cristyd43a46b2010-01-21 02:13:41 +00003797 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003798 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003799 cache_info->pixels=source_info.pixels;
3800 else
3801 {
3802 /*
3803 Create memory pixel cache.
3804 */
cristy4c08aed2011-07-01 19:47:50 +00003805 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003806 if (image->debug != MagickFalse)
3807 {
cristy32cacff2011-12-31 03:36:27 +00003808 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003809 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003810 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3811 cache_info->filename,cache_info->mapped != MagickFalse ?
3812 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003813 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003814 format);
cristy3ed852e2009-09-05 21:47:34 +00003815 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3816 message);
3817 }
cristy3ed852e2009-09-05 21:47:34 +00003818 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003819 cache_info->metacontent=(void *) NULL;
3820 if (cache_info->metacontent_extent != 0)
3821 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003822 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003823 if ((source_info.storage_class != UndefinedClass) &&
3824 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003825 {
cristy4c08aed2011-07-01 19:47:50 +00003826 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003827 exception);
3828 RelinquishPixelCachePixels(&source_info);
3829 }
cristy4c08aed2011-07-01 19:47:50 +00003830 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003831 }
3832 }
3833 RelinquishMagickResource(MemoryResource,cache_info->length);
3834 }
3835 /*
3836 Create pixel cache on disk.
3837 */
3838 status=AcquireMagickResource(DiskResource,cache_info->length);
3839 if (status == MagickFalse)
3840 {
3841 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003842 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003843 return(MagickFalse);
3844 }
cristy413f1302012-01-01 17:48:27 +00003845 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3846 {
3847 (void) ClosePixelCacheOnDisk(cache_info);
3848 *cache_info->cache_filename='\0';
3849 }
cristy3ed852e2009-09-05 21:47:34 +00003850 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3851 {
3852 RelinquishMagickResource(DiskResource,cache_info->length);
3853 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3854 image->filename);
3855 return(MagickFalse);
3856 }
3857 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3858 cache_info->length);
3859 if (status == MagickFalse)
3860 {
3861 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3862 image->filename);
3863 return(MagickFalse);
3864 }
cristyed231572011-07-14 02:18:59 +00003865 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003866 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003867 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003868 cache_info->type=DiskCache;
3869 else
3870 {
3871 status=AcquireMagickResource(MapResource,cache_info->length);
3872 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3873 (cache_info->type != MemoryCache))
3874 cache_info->type=DiskCache;
3875 else
3876 {
cristy4c08aed2011-07-01 19:47:50 +00003877 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003878 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003879 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003880 {
cristy3ed852e2009-09-05 21:47:34 +00003881 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003882 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003883 }
3884 else
3885 {
3886 /*
3887 Create file-backed memory-mapped pixel cache.
3888 */
cristy4c08aed2011-07-01 19:47:50 +00003889 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003890 (void) ClosePixelCacheOnDisk(cache_info);
3891 cache_info->type=MapCache;
3892 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003893 cache_info->metacontent=(void *) NULL;
3894 if (cache_info->metacontent_extent != 0)
3895 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003896 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003897 if ((source_info.storage_class != UndefinedClass) &&
3898 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003899 {
3900 status=ClonePixelCachePixels(cache_info,&source_info,
3901 exception);
3902 RelinquishPixelCachePixels(&source_info);
3903 }
3904 if (image->debug != MagickFalse)
3905 {
cristy413f1302012-01-01 17:48:27 +00003906 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003907 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003908 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003909 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003910 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003911 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003912 format);
cristy3ed852e2009-09-05 21:47:34 +00003913 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3914 message);
3915 }
cristy4c08aed2011-07-01 19:47:50 +00003916 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003917 }
3918 }
3919 RelinquishMagickResource(MapResource,cache_info->length);
3920 }
cristy4c08aed2011-07-01 19:47:50 +00003921 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003922 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003923 {
3924 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3925 RelinquishPixelCachePixels(&source_info);
3926 }
3927 if (image->debug != MagickFalse)
3928 {
cristyb9080c92009-12-01 20:13:26 +00003929 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003930 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003931 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003932 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003933 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003934 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003935 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3936 }
cristy4c08aed2011-07-01 19:47:50 +00003937 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003938}
3939
3940/*
3941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3942% %
3943% %
3944% %
3945+ P e r s i s t P i x e l C a c h e %
3946% %
3947% %
3948% %
3949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3950%
3951% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3952% persistent pixel cache is one that resides on disk and is not destroyed
3953% when the program exits.
3954%
3955% The format of the PersistPixelCache() method is:
3956%
3957% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3958% const MagickBooleanType attach,MagickOffsetType *offset,
3959% ExceptionInfo *exception)
3960%
3961% A description of each parameter follows:
3962%
3963% o image: the image.
3964%
3965% o filename: the persistent pixel cache filename.
3966%
cristyf3a6a9d2010-11-07 21:02:56 +00003967% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003968%
cristy3ed852e2009-09-05 21:47:34 +00003969% o initialize: A value other than zero initializes the persistent pixel
3970% cache.
3971%
3972% o offset: the offset in the persistent cache to store pixels.
3973%
3974% o exception: return any errors or warnings in this structure.
3975%
3976*/
3977MagickExport MagickBooleanType PersistPixelCache(Image *image,
3978 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3979 ExceptionInfo *exception)
3980{
3981 CacheInfo
3982 *cache_info,
3983 *clone_info;
3984
3985 Image
3986 clone_image;
3987
cristy3ed852e2009-09-05 21:47:34 +00003988 MagickBooleanType
3989 status;
3990
cristye076a6e2010-08-15 19:59:43 +00003991 ssize_t
3992 page_size;
3993
cristy3ed852e2009-09-05 21:47:34 +00003994 assert(image != (Image *) NULL);
3995 assert(image->signature == MagickSignature);
3996 if (image->debug != MagickFalse)
3997 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3998 assert(image->cache != (void *) NULL);
3999 assert(filename != (const char *) NULL);
4000 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004001 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004002 cache_info=(CacheInfo *) image->cache;
4003 assert(cache_info->signature == MagickSignature);
4004 if (attach != MagickFalse)
4005 {
4006 /*
cristy01b7eb02009-09-10 23:10:14 +00004007 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004008 */
4009 if (image->debug != MagickFalse)
4010 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004011 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004012 (void) CopyMagickString(cache_info->cache_filename,filename,
4013 MaxTextExtent);
4014 cache_info->type=DiskCache;
4015 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004016 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004017 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004018 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004019 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004020 }
cristy01b7eb02009-09-10 23:10:14 +00004021 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4022 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004023 {
cristyf84a1932010-01-03 18:00:18 +00004024 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004025 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004026 (cache_info->reference_count == 1))
4027 {
4028 int
4029 status;
4030
4031 /*
cristy01b7eb02009-09-10 23:10:14 +00004032 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004033 */
cristy320684d2011-09-23 14:55:47 +00004034 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004035 if (status == 0)
4036 {
4037 (void) CopyMagickString(cache_info->cache_filename,filename,
4038 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004039 *offset+=cache_info->length+page_size-(cache_info->length %
4040 page_size);
cristyf84a1932010-01-03 18:00:18 +00004041 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004042 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004043 if (image->debug != MagickFalse)
4044 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4045 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004046 return(MagickTrue);
4047 }
4048 }
cristyf84a1932010-01-03 18:00:18 +00004049 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004050 }
4051 /*
cristy01b7eb02009-09-10 23:10:14 +00004052 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004053 */
4054 clone_image=(*image);
4055 clone_info=(CacheInfo *) clone_image.cache;
4056 image->cache=ClonePixelCache(cache_info);
4057 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4058 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4059 cache_info->type=DiskCache;
4060 cache_info->offset=(*offset);
4061 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004062 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004063 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004064 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004065 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004066 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4067 return(status);
4068}
4069
4070/*
4071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4072% %
4073% %
4074% %
cristyc11dace2012-01-24 16:39:46 +00004075+ 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 +00004076% %
4077% %
4078% %
4079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4080%
cristyc11dace2012-01-24 16:39:46 +00004081% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4082% defined by the region rectangle and returns a pointer to the region. This
4083% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004084% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4085% pixels are transferred, otherwise a NULL is returned.
4086%
cristyc11dace2012-01-24 16:39:46 +00004087% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004088%
cristyc11dace2012-01-24 16:39:46 +00004089% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004090% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004091% const MagickBooleanType clone,NexusInfo *nexus_info,
4092% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004093%
4094% A description of each parameter follows:
4095%
4096% o image: the image.
4097%
4098% o x,y,columns,rows: These values define the perimeter of a region of
4099% pixels.
4100%
4101% o nexus_info: the cache nexus to set.
4102%
cristy65dbf172011-10-06 17:32:04 +00004103% o clone: clone the pixel cache.
4104%
cristy3ed852e2009-09-05 21:47:34 +00004105% o exception: return any errors or warnings in this structure.
4106%
4107*/
cristyc11dace2012-01-24 16:39:46 +00004108MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4109 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004110 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004111{
4112 CacheInfo
4113 *cache_info;
4114
4115 MagickOffsetType
4116 offset;
4117
4118 MagickSizeType
4119 number_pixels;
4120
4121 RectangleInfo
4122 region;
4123
4124 /*
4125 Validate pixel cache geometry.
4126 */
cristye7cc7cf2010-09-21 13:26:47 +00004127 assert(image != (const Image *) NULL);
4128 assert(image->signature == MagickSignature);
4129 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004130 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004131 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004132 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004133 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004134 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4135 {
4136 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004137 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004138 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004139 }
cristybb503372010-05-27 20:51:26 +00004140 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4141 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004142 {
4143 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004144 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004145 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004146 }
4147 offset=(MagickOffsetType) y*cache_info->columns+x;
4148 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004149 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004150 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4151 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4152 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004153 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004154 /*
4155 Return pixel cache.
4156 */
4157 region.x=x;
4158 region.y=y;
4159 region.width=columns;
4160 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004161 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004162}
4163
4164/*
4165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4166% %
4167% %
4168% %
4169+ 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 %
4170% %
4171% %
4172% %
4173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4174%
4175% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4176% defined by the region rectangle and returns a pointer to the region. This
4177% region is subsequently transferred from the pixel cache with
4178% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4179% pixels are transferred, otherwise a NULL is returned.
4180%
4181% The format of the QueueAuthenticPixelsCache() method is:
4182%
cristy4c08aed2011-07-01 19:47:50 +00004183% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004184% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004185% ExceptionInfo *exception)
4186%
4187% A description of each parameter follows:
4188%
4189% o image: the image.
4190%
4191% o x,y,columns,rows: These values define the perimeter of a region of
4192% pixels.
4193%
4194% o exception: return any errors or warnings in this structure.
4195%
4196*/
cristy4c08aed2011-07-01 19:47:50 +00004197static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004198 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004199 ExceptionInfo *exception)
4200{
4201 CacheInfo
4202 *cache_info;
4203
cristy5c9e6f22010-09-17 17:31:01 +00004204 const int
4205 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004206
cristy4c08aed2011-07-01 19:47:50 +00004207 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004208 *q;
cristy4c08aed2011-07-01 19:47:50 +00004209
cristye7cc7cf2010-09-21 13:26:47 +00004210 assert(image != (const Image *) NULL);
4211 assert(image->signature == MagickSignature);
4212 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004213 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004214 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004215 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004216 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004217 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004218 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004219}
4220
4221/*
4222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4223% %
4224% %
4225% %
4226% Q u e u e A u t h e n t i c P i x e l s %
4227% %
4228% %
4229% %
4230%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4231%
4232% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004233% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004234% region is returned, otherwise NULL is returned. The returned pointer may
4235% point to a temporary working buffer for the pixels or it may point to the
4236% final location of the pixels in memory.
4237%
4238% Write-only access means that any existing pixel values corresponding to
4239% the region are ignored. This is useful if the initial image is being
4240% created from scratch, or if the existing pixel values are to be
4241% completely replaced without need to refer to their pre-existing values.
4242% The application is free to read and write the pixel buffer returned by
4243% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4244% initialize the pixel array values. Initializing pixel array values is the
4245% application's responsibility.
4246%
4247% Performance is maximized if the selected region is part of one row, or
4248% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004249% pixels in-place (without a copy) if the image is in memory, or in a
4250% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004251% by the user.
4252%
4253% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004254% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4255% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4256% obtain the meta-content (of type void) corresponding to the region.
4257% Once the Quantum (and/or Quantum) array has been updated, the
4258% changes must be saved back to the underlying image using
4259% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004260%
4261% The format of the QueueAuthenticPixels() method is:
4262%
cristy4c08aed2011-07-01 19:47:50 +00004263% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004264% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004265% ExceptionInfo *exception)
4266%
4267% A description of each parameter follows:
4268%
4269% o image: the image.
4270%
4271% o x,y,columns,rows: These values define the perimeter of a region of
4272% pixels.
4273%
4274% o exception: return any errors or warnings in this structure.
4275%
4276*/
cristy4c08aed2011-07-01 19:47:50 +00004277MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004278 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004279 ExceptionInfo *exception)
4280{
4281 CacheInfo
4282 *cache_info;
4283
cristy2036f5c2010-09-19 21:18:17 +00004284 const int
4285 id = GetOpenMPThreadId();
4286
cristy4c08aed2011-07-01 19:47:50 +00004287 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004288 *q;
cristy4c08aed2011-07-01 19:47:50 +00004289
cristy3ed852e2009-09-05 21:47:34 +00004290 assert(image != (Image *) NULL);
4291 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004292 assert(image->cache != (Cache) NULL);
4293 cache_info=(CacheInfo *) image->cache;
4294 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004295 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004296 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004297 {
cristyc36c8822012-02-14 14:02:36 +00004298 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4299 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004300 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004301 }
cristy2036f5c2010-09-19 21:18:17 +00004302 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004303 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004304 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004305 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004306}
4307
4308/*
4309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4310% %
4311% %
4312% %
cristy4c08aed2011-07-01 19:47:50 +00004313+ 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 +00004314% %
4315% %
4316% %
4317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4318%
cristy4c08aed2011-07-01 19:47:50 +00004319% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004320% the pixel cache.
4321%
cristy4c08aed2011-07-01 19:47:50 +00004322% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004323%
cristy4c08aed2011-07-01 19:47:50 +00004324% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004325% NexusInfo *nexus_info,ExceptionInfo *exception)
4326%
4327% A description of each parameter follows:
4328%
4329% o cache_info: the pixel cache.
4330%
cristy4c08aed2011-07-01 19:47:50 +00004331% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004332%
4333% o exception: return any errors or warnings in this structure.
4334%
4335*/
cristy4c08aed2011-07-01 19:47:50 +00004336static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004337 NexusInfo *nexus_info,ExceptionInfo *exception)
4338{
4339 MagickOffsetType
4340 count,
4341 offset;
4342
4343 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004344 extent,
4345 length;
cristy3ed852e2009-09-05 21:47:34 +00004346
cristybb503372010-05-27 20:51:26 +00004347 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004348 y;
4349
cristy4c08aed2011-07-01 19:47:50 +00004350 register unsigned char
4351 *restrict q;
4352
cristybb503372010-05-27 20:51:26 +00004353 size_t
cristy3ed852e2009-09-05 21:47:34 +00004354 rows;
4355
cristy4c08aed2011-07-01 19:47:50 +00004356 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004357 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004358 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004359 return(MagickTrue);
4360 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4361 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004362 length=(MagickSizeType) nexus_info->region.width*
4363 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004364 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004365 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004366 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004367 switch (cache_info->type)
4368 {
4369 case MemoryCache:
4370 case MapCache:
4371 {
cristy4c08aed2011-07-01 19:47:50 +00004372 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004373 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004374
4375 /*
cristy4c08aed2011-07-01 19:47:50 +00004376 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004377 */
cristydd341db2010-03-04 19:06:38 +00004378 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004379 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004380 {
cristy48078b12010-09-23 17:11:01 +00004381 length=extent;
cristydd341db2010-03-04 19:06:38 +00004382 rows=1UL;
4383 }
cristy4c08aed2011-07-01 19:47:50 +00004384 p=(unsigned char *) cache_info->metacontent+offset*
4385 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004386 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004387 {
cristy8f036fe2010-09-18 02:02:00 +00004388 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004389 p+=cache_info->metacontent_extent*cache_info->columns;
4390 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004391 }
4392 break;
4393 }
4394 case DiskCache:
4395 {
4396 /*
cristy4c08aed2011-07-01 19:47:50 +00004397 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004398 */
4399 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4400 {
4401 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4402 cache_info->cache_filename);
4403 return(MagickFalse);
4404 }
cristydd341db2010-03-04 19:06:38 +00004405 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004406 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004407 {
cristy48078b12010-09-23 17:11:01 +00004408 length=extent;
cristydd341db2010-03-04 19:06:38 +00004409 rows=1UL;
4410 }
cristy48078b12010-09-23 17:11:01 +00004411 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004412 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004413 {
cristy48078b12010-09-23 17:11:01 +00004414 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004415 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004416 cache_info->metacontent_extent,length,(unsigned char *) q);
4417 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004418 break;
4419 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004420 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004421 }
cristyc11dace2012-01-24 16:39:46 +00004422 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4423 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004424 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004425 {
4426 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4427 cache_info->cache_filename);
4428 return(MagickFalse);
4429 }
4430 break;
4431 }
4432 default:
4433 break;
4434 }
4435 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004436 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004437 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004438 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004439 nexus_info->region.width,(double) nexus_info->region.height,(double)
4440 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004441 return(MagickTrue);
4442}
4443
4444/*
4445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4446% %
4447% %
4448% %
4449+ R e a d P i x e l C a c h e P i x e l s %
4450% %
4451% %
4452% %
4453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4454%
4455% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4456% cache.
4457%
4458% The format of the ReadPixelCachePixels() method is:
4459%
4460% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4461% NexusInfo *nexus_info,ExceptionInfo *exception)
4462%
4463% A description of each parameter follows:
4464%
4465% o cache_info: the pixel cache.
4466%
4467% o nexus_info: the cache nexus to read the pixels.
4468%
4469% o exception: return any errors or warnings in this structure.
4470%
4471*/
4472static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4473 NexusInfo *nexus_info,ExceptionInfo *exception)
4474{
4475 MagickOffsetType
4476 count,
4477 offset;
4478
4479 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004480 extent,
4481 length;
cristy3ed852e2009-09-05 21:47:34 +00004482
cristy4c08aed2011-07-01 19:47:50 +00004483 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004484 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004485
cristye076a6e2010-08-15 19:59:43 +00004486 register ssize_t
4487 y;
4488
cristybb503372010-05-27 20:51:26 +00004489 size_t
cristy3ed852e2009-09-05 21:47:34 +00004490 rows;
4491
cristy4c08aed2011-07-01 19:47:50 +00004492 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004493 return(MagickTrue);
4494 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4495 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004496 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004497 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004498 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004499 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004500 q=nexus_info->pixels;
4501 switch (cache_info->type)
4502 {
4503 case MemoryCache:
4504 case MapCache:
4505 {
cristy4c08aed2011-07-01 19:47:50 +00004506 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004507 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004508
4509 /*
4510 Read pixels from memory.
4511 */
cristydd341db2010-03-04 19:06:38 +00004512 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004513 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004514 {
cristy48078b12010-09-23 17:11:01 +00004515 length=extent;
cristydd341db2010-03-04 19:06:38 +00004516 rows=1UL;
4517 }
cristyed231572011-07-14 02:18:59 +00004518 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004519 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004520 {
cristy8f036fe2010-09-18 02:02:00 +00004521 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004522 p+=cache_info->number_channels*cache_info->columns;
4523 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004524 }
4525 break;
4526 }
4527 case DiskCache:
4528 {
4529 /*
4530 Read pixels from disk.
4531 */
4532 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4533 {
4534 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4535 cache_info->cache_filename);
4536 return(MagickFalse);
4537 }
cristydd341db2010-03-04 19:06:38 +00004538 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004539 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004540 {
cristy48078b12010-09-23 17:11:01 +00004541 length=extent;
cristydd341db2010-03-04 19:06:38 +00004542 rows=1UL;
4543 }
cristybb503372010-05-27 20:51:26 +00004544 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004545 {
4546 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004547 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004548 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004549 break;
4550 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004551 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004552 }
cristyc11dace2012-01-24 16:39:46 +00004553 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4554 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004555 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004556 {
4557 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4558 cache_info->cache_filename);
4559 return(MagickFalse);
4560 }
4561 break;
4562 }
4563 default:
4564 break;
4565 }
4566 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004567 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004568 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004569 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004570 nexus_info->region.width,(double) nexus_info->region.height,(double)
4571 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004572 return(MagickTrue);
4573}
4574
4575/*
4576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4577% %
4578% %
4579% %
4580+ R e f e r e n c e P i x e l C a c h e %
4581% %
4582% %
4583% %
4584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4585%
4586% ReferencePixelCache() increments the reference count associated with the
4587% pixel cache returning a pointer to the cache.
4588%
4589% The format of the ReferencePixelCache method is:
4590%
4591% Cache ReferencePixelCache(Cache cache_info)
4592%
4593% A description of each parameter follows:
4594%
4595% o cache_info: the pixel cache.
4596%
4597*/
cristya6577ff2011-09-02 19:54:26 +00004598MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004599{
4600 CacheInfo
4601 *cache_info;
4602
4603 assert(cache != (Cache *) NULL);
4604 cache_info=(CacheInfo *) cache;
4605 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004606 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004607 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004608 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004609 return(cache_info);
4610}
4611
4612/*
4613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4614% %
4615% %
4616% %
4617+ S e t P i x e l C a c h e M e t h o d s %
4618% %
4619% %
4620% %
4621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4622%
4623% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4624%
4625% The format of the SetPixelCacheMethods() method is:
4626%
4627% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4628%
4629% A description of each parameter follows:
4630%
4631% o cache: the pixel cache.
4632%
4633% o cache_methods: Specifies a pointer to a CacheMethods structure.
4634%
4635*/
cristya6577ff2011-09-02 19:54:26 +00004636MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004637{
4638 CacheInfo
4639 *cache_info;
4640
4641 GetOneAuthenticPixelFromHandler
4642 get_one_authentic_pixel_from_handler;
4643
4644 GetOneVirtualPixelFromHandler
4645 get_one_virtual_pixel_from_handler;
4646
4647 /*
4648 Set cache pixel methods.
4649 */
4650 assert(cache != (Cache) NULL);
4651 assert(cache_methods != (CacheMethods *) NULL);
4652 cache_info=(CacheInfo *) cache;
4653 assert(cache_info->signature == MagickSignature);
4654 if (cache_info->debug != MagickFalse)
4655 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4656 cache_info->filename);
4657 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4658 cache_info->methods.get_virtual_pixel_handler=
4659 cache_methods->get_virtual_pixel_handler;
4660 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4661 cache_info->methods.destroy_pixel_handler=
4662 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004663 if (cache_methods->get_virtual_metacontent_from_handler !=
4664 (GetVirtualMetacontentFromHandler) NULL)
4665 cache_info->methods.get_virtual_metacontent_from_handler=
4666 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004667 if (cache_methods->get_authentic_pixels_handler !=
4668 (GetAuthenticPixelsHandler) NULL)
4669 cache_info->methods.get_authentic_pixels_handler=
4670 cache_methods->get_authentic_pixels_handler;
4671 if (cache_methods->queue_authentic_pixels_handler !=
4672 (QueueAuthenticPixelsHandler) NULL)
4673 cache_info->methods.queue_authentic_pixels_handler=
4674 cache_methods->queue_authentic_pixels_handler;
4675 if (cache_methods->sync_authentic_pixels_handler !=
4676 (SyncAuthenticPixelsHandler) NULL)
4677 cache_info->methods.sync_authentic_pixels_handler=
4678 cache_methods->sync_authentic_pixels_handler;
4679 if (cache_methods->get_authentic_pixels_from_handler !=
4680 (GetAuthenticPixelsFromHandler) NULL)
4681 cache_info->methods.get_authentic_pixels_from_handler=
4682 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004683 if (cache_methods->get_authentic_metacontent_from_handler !=
4684 (GetAuthenticMetacontentFromHandler) NULL)
4685 cache_info->methods.get_authentic_metacontent_from_handler=
4686 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004687 get_one_virtual_pixel_from_handler=
4688 cache_info->methods.get_one_virtual_pixel_from_handler;
4689 if (get_one_virtual_pixel_from_handler !=
4690 (GetOneVirtualPixelFromHandler) NULL)
4691 cache_info->methods.get_one_virtual_pixel_from_handler=
4692 cache_methods->get_one_virtual_pixel_from_handler;
4693 get_one_authentic_pixel_from_handler=
4694 cache_methods->get_one_authentic_pixel_from_handler;
4695 if (get_one_authentic_pixel_from_handler !=
4696 (GetOneAuthenticPixelFromHandler) NULL)
4697 cache_info->methods.get_one_authentic_pixel_from_handler=
4698 cache_methods->get_one_authentic_pixel_from_handler;
4699}
4700
4701/*
4702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703% %
4704% %
4705% %
4706+ S e t P i x e l C a c h e N e x u s P i x e l s %
4707% %
4708% %
4709% %
4710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4711%
4712% SetPixelCacheNexusPixels() defines the region of the cache for the
4713% specified cache nexus.
4714%
4715% The format of the SetPixelCacheNexusPixels() method is:
4716%
cristy265a2b22012-05-11 12:48:50 +00004717% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004718% const RectangleInfo *region,NexusInfo *nexus_info,
4719% ExceptionInfo *exception)
4720%
4721% A description of each parameter follows:
4722%
4723% o image: the image.
4724%
cristy265a2b22012-05-11 12:48:50 +00004725% o mode: ReadMode, WriteMode, or IOMode.
4726%
cristy3ed852e2009-09-05 21:47:34 +00004727% o region: A pointer to the RectangleInfo structure that defines the
4728% region of this particular cache nexus.
4729%
4730% o nexus_info: the cache nexus to set.
4731%
4732% o exception: return any errors or warnings in this structure.
4733%
4734*/
cristyabd6e372010-09-15 19:11:26 +00004735
cristyf1832792012-05-08 18:38:18 +00004736static inline MagickBooleanType AcquireCacheNexusPixels(
4737 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4738 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004739{
4740 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4741 return(MagickFalse);
4742 nexus_info->mapped=MagickFalse;
cristy64c3edf2012-04-13 18:50:13 +00004743 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00004744 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004745 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004746 {
4747 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004748 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004749 nexus_info->length);
4750 }
cristy4c08aed2011-07-01 19:47:50 +00004751 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004752 {
4753 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004754 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004755 cache_info->filename);
4756 return(MagickFalse);
4757 }
4758 return(MagickTrue);
4759}
4760
cristyadf82722012-05-11 17:34:16 +00004761static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4762 const MapMode mode)
4763{
cristyfc5845e2012-05-11 18:18:13 +00004764 if (mode == ReadMode)
4765 {
4766 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4767 return;
4768 }
4769 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
cristyadf82722012-05-11 17:34:16 +00004770}
4771
cristy265a2b22012-05-11 12:48:50 +00004772static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004773 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4774{
4775 CacheInfo
4776 *cache_info;
4777
4778 MagickBooleanType
4779 status;
4780
cristy3ed852e2009-09-05 21:47:34 +00004781 MagickSizeType
4782 length,
4783 number_pixels;
4784
cristy3ed852e2009-09-05 21:47:34 +00004785 cache_info=(CacheInfo *) image->cache;
4786 assert(cache_info->signature == MagickSignature);
4787 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004788 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004789 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004790 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004791 {
cristybb503372010-05-27 20:51:26 +00004792 ssize_t
cristybad067a2010-02-15 17:20:55 +00004793 x,
4794 y;
cristy3ed852e2009-09-05 21:47:34 +00004795
cristyeaedf062010-05-29 22:36:02 +00004796 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4797 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004798 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4799 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004800 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004801 ((nexus_info->region.width == cache_info->columns) ||
4802 ((nexus_info->region.width % cache_info->columns) == 0)))))
4803 {
4804 MagickOffsetType
4805 offset;
4806
4807 /*
4808 Pixels are accessed directly from memory.
4809 */
4810 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4811 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004812 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004813 offset;
4814 nexus_info->metacontent=(void *) NULL;
4815 if (cache_info->metacontent_extent != 0)
4816 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4817 offset*cache_info->metacontent_extent;
cristyadf82722012-05-11 17:34:16 +00004818 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy731c3532010-02-15 15:40:03 +00004819 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004820 }
4821 }
4822 /*
4823 Pixels are stored in a cache region until they are synced to the cache.
4824 */
4825 number_pixels=(MagickSizeType) nexus_info->region.width*
4826 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004827 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004828 if (cache_info->metacontent_extent != 0)
4829 length+=number_pixels*cache_info->metacontent_extent;
4830 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004831 {
4832 nexus_info->length=length;
4833 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4834 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004835 {
4836 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004837 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004838 }
cristy3ed852e2009-09-05 21:47:34 +00004839 }
4840 else
4841 if (nexus_info->length != length)
4842 {
4843 RelinquishCacheNexusPixels(nexus_info);
4844 nexus_info->length=length;
4845 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4846 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004847 {
4848 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004849 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004850 }
cristy3ed852e2009-09-05 21:47:34 +00004851 }
4852 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004853 nexus_info->metacontent=(void *) NULL;
4854 if (cache_info->metacontent_extent != 0)
4855 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004856 cache_info->number_channels);
cristyadf82722012-05-11 17:34:16 +00004857 PrefetchPixelCacheNexusPixels(nexus_info,mode);
cristy3ed852e2009-09-05 21:47:34 +00004858 return(nexus_info->pixels);
4859}
4860
4861/*
4862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4863% %
4864% %
4865% %
4866% S e t P i x e l C a c h e V i r t u a l M e t h o d %
4867% %
4868% %
4869% %
4870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871%
4872% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4873% pixel cache and returns the previous setting. A virtual pixel is any pixel
4874% access that is outside the boundaries of the image cache.
4875%
4876% The format of the SetPixelCacheVirtualMethod() method is:
4877%
cristy387430f2012-02-07 13:09:46 +00004878% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4879% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004880%
4881% A description of each parameter follows:
4882%
4883% o image: the image.
4884%
4885% o virtual_pixel_method: choose the type of virtual pixel.
4886%
cristy387430f2012-02-07 13:09:46 +00004887% o exception: return any errors or warnings in this structure.
4888%
cristy3ed852e2009-09-05 21:47:34 +00004889*/
cristy3d4cb882012-02-07 19:11:26 +00004890
4891static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4892 ExceptionInfo *exception)
4893{
4894 CacheInfo
4895 *cache_info;
4896
cristyf2719112012-05-06 18:38:46 +00004897 CacheView
4898 *image_view;
4899
cristy3d4cb882012-02-07 19:11:26 +00004900 MagickBooleanType
4901 status;
4902
4903 ssize_t
4904 y;
4905
4906 assert(image != (Image *) NULL);
4907 assert(image->signature == MagickSignature);
4908 if (image->debug != MagickFalse)
4909 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4910 assert(image->cache != (Cache) NULL);
4911 cache_info=(CacheInfo *) image->cache;
4912 assert(cache_info->signature == MagickSignature);
4913 image->matte=MagickTrue;
4914 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004915 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004916#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00004917 #pragma omp parallel for schedule(static) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00004918 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004919#endif
4920 for (y=0; y < (ssize_t) image->rows; y++)
4921 {
cristy3d4cb882012-02-07 19:11:26 +00004922 register Quantum
4923 *restrict q;
4924
4925 register ssize_t
4926 x;
4927
4928 if (status == MagickFalse)
4929 continue;
cristy23d198a2012-03-13 13:48:08 +00004930 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004931 if (q == (Quantum *) NULL)
4932 {
4933 status=MagickFalse;
4934 continue;
4935 }
4936 for (x=0; x < (ssize_t) image->columns; x++)
4937 {
4938 SetPixelAlpha(image,alpha,q);
4939 q+=GetPixelChannels(image);
4940 }
cristy23d198a2012-03-13 13:48:08 +00004941 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004942 }
cristy23d198a2012-03-13 13:48:08 +00004943 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004944 return(status);
4945}
4946
cristy387430f2012-02-07 13:09:46 +00004947MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4948 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004949{
4950 CacheInfo
4951 *cache_info;
4952
4953 VirtualPixelMethod
4954 method;
4955
4956 assert(image != (Image *) NULL);
4957 assert(image->signature == MagickSignature);
4958 if (image->debug != MagickFalse)
4959 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4960 assert(image->cache != (Cache) NULL);
4961 cache_info=(CacheInfo *) image->cache;
4962 assert(cache_info->signature == MagickSignature);
4963 method=cache_info->virtual_pixel_method;
4964 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy13c10082012-05-29 11:22:12 +00004965 if ((image->columns != 0) && (image->rows != 0))
4966 switch (virtual_pixel_method)
cristy387430f2012-02-07 13:09:46 +00004967 {
cristy13c10082012-05-29 11:22:12 +00004968 case BackgroundVirtualPixelMethod:
4969 {
4970 if ((image->background_color.matte != MagickFalse) &&
4971 (image->matte == MagickFalse))
4972 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy6386b792012-06-23 17:44:57 +00004973 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4974 (IsGrayColorspace(image->colorspace) != MagickFalse))
cristyb09db112012-07-11 12:04:31 +00004975 (void) TransformImageColorspace(image,RGBColorspace,exception);
cristy13c10082012-05-29 11:22:12 +00004976 break;
4977 }
4978 case TransparentVirtualPixelMethod:
4979 {
4980 if (image->matte == MagickFalse)
4981 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4982 break;
4983 }
4984 default:
4985 break;
cristy387430f2012-02-07 13:09:46 +00004986 }
cristy3ed852e2009-09-05 21:47:34 +00004987 return(method);
4988}
4989
4990/*
4991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4992% %
4993% %
4994% %
4995+ 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 %
4996% %
4997% %
4998% %
4999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5000%
5001% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5002% in-memory or disk cache. The method returns MagickTrue if the pixel region
5003% is synced, otherwise MagickFalse.
5004%
5005% The format of the SyncAuthenticPixelCacheNexus() method is:
5006%
5007% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5008% NexusInfo *nexus_info,ExceptionInfo *exception)
5009%
5010% A description of each parameter follows:
5011%
5012% o image: the image.
5013%
5014% o nexus_info: the cache nexus to sync.
5015%
5016% o exception: return any errors or warnings in this structure.
5017%
5018*/
cristya6577ff2011-09-02 19:54:26 +00005019MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005020 NexusInfo *nexus_info,ExceptionInfo *exception)
5021{
5022 CacheInfo
5023 *cache_info;
5024
5025 MagickBooleanType
5026 status;
5027
5028 /*
5029 Transfer pixels to the cache.
5030 */
5031 assert(image != (Image *) NULL);
5032 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005033 if (image->cache == (Cache) NULL)
5034 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5035 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005036 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005037 if (cache_info->type == UndefinedCache)
5038 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005039 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005040 return(MagickTrue);
5041 assert(cache_info->signature == MagickSignature);
5042 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005043 if ((cache_info->metacontent_extent != 0) &&
5044 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005045 return(MagickFalse);
5046 return(status);
5047}
5048
5049/*
5050%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5051% %
5052% %
5053% %
5054+ S y n c A u t h e n t i c P i x e l C a c h e %
5055% %
5056% %
5057% %
5058%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5059%
5060% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5061% or disk cache. The method returns MagickTrue if the pixel region is synced,
5062% otherwise MagickFalse.
5063%
5064% The format of the SyncAuthenticPixelsCache() method is:
5065%
5066% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5067% ExceptionInfo *exception)
5068%
5069% A description of each parameter follows:
5070%
5071% o image: the image.
5072%
5073% o exception: return any errors or warnings in this structure.
5074%
5075*/
5076static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5077 ExceptionInfo *exception)
5078{
5079 CacheInfo
5080 *cache_info;
5081
cristy5c9e6f22010-09-17 17:31:01 +00005082 const int
5083 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005084
cristy4c08aed2011-07-01 19:47:50 +00005085 MagickBooleanType
5086 status;
5087
cristye7cc7cf2010-09-21 13:26:47 +00005088 assert(image != (Image *) NULL);
5089 assert(image->signature == MagickSignature);
5090 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005091 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005092 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005093 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005094 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5095 exception);
5096 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005097}
5098
5099/*
5100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5101% %
5102% %
5103% %
5104% S y n c A u t h e n t i c P i x e l s %
5105% %
5106% %
5107% %
5108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5109%
5110% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5111% The method returns MagickTrue if the pixel region is flushed, otherwise
5112% MagickFalse.
5113%
5114% The format of the SyncAuthenticPixels() method is:
5115%
5116% MagickBooleanType SyncAuthenticPixels(Image *image,
5117% ExceptionInfo *exception)
5118%
5119% A description of each parameter follows:
5120%
5121% o image: the image.
5122%
5123% o exception: return any errors or warnings in this structure.
5124%
5125*/
5126MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5127 ExceptionInfo *exception)
5128{
5129 CacheInfo
5130 *cache_info;
5131
cristy2036f5c2010-09-19 21:18:17 +00005132 const int
5133 id = GetOpenMPThreadId();
5134
cristy4c08aed2011-07-01 19:47:50 +00005135 MagickBooleanType
5136 status;
5137
cristy3ed852e2009-09-05 21:47:34 +00005138 assert(image != (Image *) NULL);
5139 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005140 assert(image->cache != (Cache) NULL);
5141 cache_info=(CacheInfo *) image->cache;
5142 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005143 if (cache_info->methods.sync_authentic_pixels_handler !=
5144 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005145 {
5146 status=cache_info->methods.sync_authentic_pixels_handler(image,
5147 exception);
5148 return(status);
5149 }
cristy2036f5c2010-09-19 21:18:17 +00005150 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005151 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5152 exception);
5153 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005154}
5155
5156/*
5157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5158% %
5159% %
5160% %
cristyd1dd6e42011-09-04 01:46:08 +00005161+ 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 +00005162% %
5163% %
5164% %
5165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5166%
5167% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5168% The method returns MagickTrue if the pixel region is flushed, otherwise
5169% MagickFalse.
5170%
5171% The format of the SyncImagePixelCache() method is:
5172%
5173% MagickBooleanType SyncImagePixelCache(Image *image,
5174% ExceptionInfo *exception)
5175%
5176% A description of each parameter follows:
5177%
5178% o image: the image.
5179%
5180% o exception: return any errors or warnings in this structure.
5181%
5182*/
cristyd1dd6e42011-09-04 01:46:08 +00005183MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005184 ExceptionInfo *exception)
5185{
5186 CacheInfo
5187 *cache_info;
5188
5189 assert(image != (Image *) NULL);
5190 assert(exception != (ExceptionInfo *) NULL);
5191 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5192 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5193}
5194
5195/*
5196%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5197% %
5198% %
5199% %
cristy4c08aed2011-07-01 19:47:50 +00005200+ 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 +00005201% %
5202% %
5203% %
5204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5205%
cristy4c08aed2011-07-01 19:47:50 +00005206% WritePixelCacheMetacontent() writes the meta-content to the specified region
5207% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005208%
cristy4c08aed2011-07-01 19:47:50 +00005209% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005210%
cristy4c08aed2011-07-01 19:47:50 +00005211% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005212% NexusInfo *nexus_info,ExceptionInfo *exception)
5213%
5214% A description of each parameter follows:
5215%
5216% o cache_info: the pixel cache.
5217%
cristy4c08aed2011-07-01 19:47:50 +00005218% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005219%
5220% o exception: return any errors or warnings in this structure.
5221%
5222*/
cristy4c08aed2011-07-01 19:47:50 +00005223static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005224 NexusInfo *nexus_info,ExceptionInfo *exception)
5225{
5226 MagickOffsetType
5227 count,
5228 offset;
5229
5230 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005231 extent,
5232 length;
cristy3ed852e2009-09-05 21:47:34 +00005233
cristy4c08aed2011-07-01 19:47:50 +00005234 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005235 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005236
cristybb503372010-05-27 20:51:26 +00005237 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005238 y;
5239
cristybb503372010-05-27 20:51:26 +00005240 size_t
cristy3ed852e2009-09-05 21:47:34 +00005241 rows;
5242
cristy4c08aed2011-07-01 19:47:50 +00005243 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005244 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005245 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005246 return(MagickTrue);
5247 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5248 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005249 length=(MagickSizeType) nexus_info->region.width*
5250 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005251 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005252 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005253 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005254 switch (cache_info->type)
5255 {
5256 case MemoryCache:
5257 case MapCache:
5258 {
cristy4c08aed2011-07-01 19:47:50 +00005259 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005260 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005261
5262 /*
cristy4c08aed2011-07-01 19:47:50 +00005263 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005264 */
cristydd341db2010-03-04 19:06:38 +00005265 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005266 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005267 {
cristy48078b12010-09-23 17:11:01 +00005268 length=extent;
cristydd341db2010-03-04 19:06:38 +00005269 rows=1UL;
5270 }
cristy4c08aed2011-07-01 19:47:50 +00005271 q=(unsigned char *) cache_info->metacontent+offset*
5272 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005273 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005274 {
cristy8f036fe2010-09-18 02:02:00 +00005275 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005276 p+=nexus_info->region.width*cache_info->metacontent_extent;
5277 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005278 }
5279 break;
5280 }
5281 case DiskCache:
5282 {
5283 /*
cristy4c08aed2011-07-01 19:47:50 +00005284 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005285 */
5286 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5287 {
5288 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5289 cache_info->cache_filename);
5290 return(MagickFalse);
5291 }
cristydd341db2010-03-04 19:06:38 +00005292 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005293 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005294 {
cristy48078b12010-09-23 17:11:01 +00005295 length=extent;
cristydd341db2010-03-04 19:06:38 +00005296 rows=1UL;
5297 }
cristy48078b12010-09-23 17:11:01 +00005298 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005299 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005300 {
cristy48078b12010-09-23 17:11:01 +00005301 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005302 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005303 cache_info->metacontent_extent,length,(const unsigned char *) p);
5304 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005305 break;
cristy4c08aed2011-07-01 19:47:50 +00005306 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005307 offset+=cache_info->columns;
5308 }
cristyc11dace2012-01-24 16:39:46 +00005309 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5310 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005311 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005312 {
5313 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5314 cache_info->cache_filename);
5315 return(MagickFalse);
5316 }
5317 break;
5318 }
5319 default:
5320 break;
5321 }
5322 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005323 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005324 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005325 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005326 nexus_info->region.width,(double) nexus_info->region.height,(double)
5327 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005328 return(MagickTrue);
5329}
5330
5331/*
5332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5333% %
5334% %
5335% %
5336+ W r i t e C a c h e P i x e l s %
5337% %
5338% %
5339% %
5340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5341%
5342% WritePixelCachePixels() writes image pixels to the specified region of the
5343% pixel cache.
5344%
5345% The format of the WritePixelCachePixels() method is:
5346%
5347% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5348% NexusInfo *nexus_info,ExceptionInfo *exception)
5349%
5350% A description of each parameter follows:
5351%
5352% o cache_info: the pixel cache.
5353%
5354% o nexus_info: the cache nexus to write the pixels.
5355%
5356% o exception: return any errors or warnings in this structure.
5357%
5358*/
5359static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5360 NexusInfo *nexus_info,ExceptionInfo *exception)
5361{
5362 MagickOffsetType
5363 count,
5364 offset;
5365
5366 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005367 extent,
5368 length;
cristy3ed852e2009-09-05 21:47:34 +00005369
cristy4c08aed2011-07-01 19:47:50 +00005370 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005371 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005372
cristybb503372010-05-27 20:51:26 +00005373 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005374 y;
5375
cristybb503372010-05-27 20:51:26 +00005376 size_t
cristy3ed852e2009-09-05 21:47:34 +00005377 rows;
5378
cristy4c08aed2011-07-01 19:47:50 +00005379 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005380 return(MagickTrue);
5381 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5382 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005383 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005384 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005385 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005386 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005387 p=nexus_info->pixels;
5388 switch (cache_info->type)
5389 {
5390 case MemoryCache:
5391 case MapCache:
5392 {
cristy4c08aed2011-07-01 19:47:50 +00005393 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005394 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005395
5396 /*
5397 Write pixels to memory.
5398 */
cristydd341db2010-03-04 19:06:38 +00005399 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005400 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005401 {
cristy48078b12010-09-23 17:11:01 +00005402 length=extent;
cristydd341db2010-03-04 19:06:38 +00005403 rows=1UL;
5404 }
cristyed231572011-07-14 02:18:59 +00005405 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005406 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005407 {
cristy8f036fe2010-09-18 02:02:00 +00005408 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005409 p+=nexus_info->region.width*cache_info->number_channels;
5410 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005411 }
5412 break;
5413 }
5414 case DiskCache:
5415 {
5416 /*
5417 Write pixels to disk.
5418 */
5419 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5420 {
5421 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5422 cache_info->cache_filename);
5423 return(MagickFalse);
5424 }
cristydd341db2010-03-04 19:06:38 +00005425 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005426 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005427 {
cristy48078b12010-09-23 17:11:01 +00005428 length=extent;
cristydd341db2010-03-04 19:06:38 +00005429 rows=1UL;
5430 }
cristybb503372010-05-27 20:51:26 +00005431 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005432 {
5433 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005434 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005435 p);
5436 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005437 break;
cristyed231572011-07-14 02:18:59 +00005438 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005439 offset+=cache_info->columns;
5440 }
cristyc11dace2012-01-24 16:39:46 +00005441 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5442 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005443 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005444 {
5445 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5446 cache_info->cache_filename);
5447 return(MagickFalse);
5448 }
5449 break;
5450 }
5451 default:
5452 break;
5453 }
5454 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005455 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005456 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005457 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005458 nexus_info->region.width,(double) nexus_info->region.height,(double)
5459 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005460 return(MagickTrue);
5461}