blob: c6185d48fe1c33d8fb90bc92339c749e919ac000 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000069#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000070#if defined(MAGICKCORE_ZLIB_DELEGATE)
71#include "zlib.h"
72#endif
73
74/*
cristy30097232010-07-01 02:16:30 +000075 Define declarations.
76*/
77#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
cristyc11dace2012-01-24 16:39:46 +000078#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
79 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
cristy30097232010-07-01 02:16:30 +000080
81/*
cristy3ed852e2009-09-05 21:47:34 +000082 Typedef declarations.
83*/
84typedef struct _MagickModulo
85{
cristybb503372010-05-27 20:51:26 +000086 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000087 quotient,
88 remainder;
89} MagickModulo;
90
91struct _NexusInfo
92{
93 MagickBooleanType
94 mapped;
95
96 RectangleInfo
97 region;
98
99 MagickSizeType
100 length;
101
cristy4c08aed2011-07-01 19:47:50 +0000102 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000103 *cache,
104 *pixels;
105
cristy4c08aed2011-07-01 19:47:50 +0000106 void
107 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000108
cristybb503372010-05-27 20:51:26 +0000109 size_t
cristy3ed852e2009-09-05 21:47:34 +0000110 signature;
111};
112
113/*
114 Forward declarations.
115*/
116#if defined(__cplusplus) || defined(c_plusplus)
117extern "C" {
118#endif
119
cristy4c08aed2011-07-01 19:47:50 +0000120static const Quantum
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
cristy4c08aed2011-07-01 19:47:50 +0000125static const void
126 *GetVirtualMetacontentFromCache(const Image *);
127
cristy3ed852e2009-09-05 21:47:34 +0000128static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000129 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000130 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000131 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000132 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000133 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000134 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000135 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
136 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000137 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000138 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
139
cristy4c08aed2011-07-01 19:47:50 +0000140static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000141 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000143 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
144 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000145 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000146 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000147
148#if defined(__cplusplus) || defined(c_plusplus)
149}
150#endif
151
152/*
153 Global declarations.
154*/
155static volatile MagickBooleanType
156 instantiate_cache = MagickFalse;
157
158static SemaphoreInfo
159 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristya6577ff2011-09-02 19:54:26 +0000183MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
cristya64b85d2011-09-14 01:02:31 +0000188 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000203 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000204 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000208 return((Cache ) cache_info);
209}
210
211/*
212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213% %
214% %
215% %
216% A c q u i r e P i x e l C a c h e N e x u s %
217% %
218% %
219% %
220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221%
222% AcquirePixelCacheNexus() allocates the NexusInfo structure.
223%
224% The format of the AcquirePixelCacheNexus method is:
225%
cristybb503372010-05-27 20:51:26 +0000226% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000227%
228% A description of each parameter follows:
229%
230% o number_threads: the number of nexus threads.
231%
232*/
cristya6577ff2011-09-02 19:54:26 +0000233MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000234{
cristy3ed852e2009-09-05 21:47:34 +0000235 NexusInfo
236 **nexus_info;
237
cristye076a6e2010-08-15 19:59:43 +0000238 register ssize_t
239 i;
240
cristya64b85d2011-09-14 01:02:31 +0000241 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000242 sizeof(*nexus_info));
243 if (nexus_info == (NexusInfo **) NULL)
244 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000245 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000246 {
cristy7dc8ac52012-01-10 20:14:52 +0000247 nexus_info[i]=(NexusInfo *) AcquireQuantumMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000248 if (nexus_info[i] == (NexusInfo *) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
250 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
251 nexus_info[i]->signature=MagickSignature;
252 }
253 return(nexus_info);
254}
255
256/*
257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258% %
259% %
260% %
cristyd43a46b2010-01-21 02:13:41 +0000261+ A c q u i r e P i x e l C a c h e P i x e l s %
262% %
263% %
264% %
265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266%
267% AcquirePixelCachePixels() returns the pixels associated with the specified
268% image.
269%
270% The format of the AcquirePixelCachePixels() method is:
271%
272% const void *AcquirePixelCachePixels(const Image *image,
273% MagickSizeType *length,ExceptionInfo *exception)
274%
275% A description of each parameter follows:
276%
277% o image: the image.
278%
279% o length: the pixel cache length.
280%
281% o exception: return any errors or warnings in this structure.
282%
283*/
cristyd1dd6e42011-09-04 01:46:08 +0000284MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000285 MagickSizeType *length,ExceptionInfo *exception)
286{
287 CacheInfo
288 *cache_info;
289
290 assert(image != (const Image *) NULL);
291 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000292 assert(exception != (ExceptionInfo *) NULL);
293 assert(exception->signature == MagickSignature);
294 assert(image->cache != (Cache) NULL);
295 cache_info=(CacheInfo *) image->cache;
296 assert(cache_info->signature == MagickSignature);
297 *length=0;
298 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
299 return((const void *) NULL);
300 *length=cache_info->length;
301 return((const void *) cache_info->pixels);
302}
303
304/*
305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306% %
307% %
308% %
cristyf34a1452009-10-24 22:29:27 +0000309+ C a c h e C o m p o n e n t G e n e s i s %
310% %
311% %
312% %
313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314%
315% CacheComponentGenesis() instantiates the cache component.
316%
317% The format of the CacheComponentGenesis method is:
318%
319% MagickBooleanType CacheComponentGenesis(void)
320%
321*/
cristy5ff4eaf2011-09-03 01:38:02 +0000322MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000323{
cristy165b6092009-10-26 13:52:10 +0000324 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000325 return(MagickTrue);
326}
327
328/*
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330% %
331% %
332% %
333+ C a c h e C o m p o n e n t T e r m i n u s %
334% %
335% %
336% %
337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338%
339% CacheComponentTerminus() destroys the cache component.
340%
341% The format of the CacheComponentTerminus() method is:
342%
343% CacheComponentTerminus(void)
344%
345*/
cristy5ff4eaf2011-09-03 01:38:02 +0000346MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000347{
cristy18b17442009-10-25 18:36:48 +0000348 if (cache_semaphore == (SemaphoreInfo *) NULL)
349 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000350 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000351 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000352 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000353 DestroySemaphoreInfo(&cache_semaphore);
354}
355
356/*
357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358% %
359% %
360% %
cristy3ed852e2009-09-05 21:47:34 +0000361+ C l i p P i x e l C a c h e N e x u s %
362% %
363% %
364% %
365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366%
367% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000368% mask. It returns MagickTrue if the pixel region is clipped, otherwise
369% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000370%
371% The format of the ClipPixelCacheNexus() method is:
372%
373% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
374% ExceptionInfo *exception)
375%
376% A description of each parameter follows:
377%
378% o image: the image.
379%
380% o nexus_info: the cache nexus to clip.
381%
382% o exception: return any errors or warnings in this structure.
383%
384*/
385static MagickBooleanType ClipPixelCacheNexus(Image *image,
386 NexusInfo *nexus_info,ExceptionInfo *exception)
387{
388 CacheInfo
389 *cache_info;
390
391 MagickSizeType
392 number_pixels;
393
394 NexusInfo
395 **clip_nexus,
396 **image_nexus;
397
cristy4c08aed2011-07-01 19:47:50 +0000398 register const Quantum
399 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000400 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000401
cristy4c08aed2011-07-01 19:47:50 +0000402 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000403 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000404
cristye076a6e2010-08-15 19:59:43 +0000405 register ssize_t
cristy12006112012-01-02 17:06:42 +0000406 x;
cristye076a6e2010-08-15 19:59:43 +0000407
cristy3ed852e2009-09-05 21:47:34 +0000408 /*
cristyc57486d2012-01-02 17:46:50 +0000409 Clip the image as defined by the clipping mask.
cristy3ed852e2009-09-05 21:47:34 +0000410 */
411 if (image->debug != MagickFalse)
412 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
413 if (image->clip_mask == (Image *) NULL)
414 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000415 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000416 if (cache_info == (Cache) NULL)
417 return(MagickFalse);
418 image_nexus=AcquirePixelCacheNexus(1);
419 clip_nexus=AcquirePixelCacheNexus(1);
420 if ((image_nexus == (NexusInfo **) NULL) ||
421 (clip_nexus == (NexusInfo **) NULL))
422 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy12006112012-01-02 17:06:42 +0000423 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
424 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
425 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000426 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000427 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
428 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
429 nexus_info->region.height,clip_nexus[0],exception);
430 number_pixels=(MagickSizeType) nexus_info->region.width*
431 nexus_info->region.height;
cristy12006112012-01-02 17:06:42 +0000432 for (x=0; x < (ssize_t) number_pixels; x++)
cristy3ed852e2009-09-05 21:47:34 +0000433 {
cristy12006112012-01-02 17:06:42 +0000434 register ssize_t
435 i;
436
cristy4c08aed2011-07-01 19:47:50 +0000437 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000438 break;
cristy12006112012-01-02 17:06:42 +0000439 if (GetPixelIntensity(image->clip_mask,r) > ((Quantum) QuantumRange/2))
440 for (i=0; i < (ssize_t) image->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000441 {
cristy12006112012-01-02 17:06:42 +0000442 PixelChannel
443 channel;
444
445 PixelTrait
446 traits;
447
448 channel=GetPixelChannelMapChannel(image,i);
449 traits=GetPixelChannelMapTraits(image,channel);
cristyc57486d2012-01-02 17:46:50 +0000450 if (traits == UndefinedPixelTrait)
451 continue;
452 q[i]=p[i];
cristy3ed852e2009-09-05 21:47:34 +0000453 }
cristyed231572011-07-14 02:18:59 +0000454 p+=GetPixelChannels(image);
455 q+=GetPixelChannels(image);
456 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000457 }
458 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
459 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristy12006112012-01-02 17:06:42 +0000460 if (x < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000461 return(MagickFalse);
462 return(MagickTrue);
463}
464
465/*
466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467% %
468% %
469% %
470+ C l o n e P i x e l C a c h e %
471% %
472% %
473% %
474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475%
476% ClonePixelCache() clones a pixel cache.
477%
478% The format of the ClonePixelCache() method is:
479%
480% Cache ClonePixelCache(const Cache cache)
481%
482% A description of each parameter follows:
483%
484% o cache: the pixel cache.
485%
486*/
cristya6577ff2011-09-02 19:54:26 +0000487MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000488{
489 CacheInfo
490 *clone_info;
491
492 const CacheInfo
493 *cache_info;
494
cristy9f027d12011-09-21 01:17:17 +0000495 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000496 cache_info=(const CacheInfo *) cache;
497 assert(cache_info->signature == MagickSignature);
498 if (cache_info->debug != MagickFalse)
499 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
500 cache_info->filename);
501 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
502 if (clone_info == (Cache) NULL)
503 return((Cache) NULL);
504 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
505 return((Cache ) clone_info);
506}
507
508/*
509%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
510% %
511% %
512% %
cristy60c44a82009-10-07 00:58:49 +0000513+ 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 +0000514% %
515% %
516% %
517%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
518% ClonePixelCachePixels() clones the source pixel cache to the destination
519% cache.
520%
521% The format of the ClonePixelCachePixels() method is:
522%
523% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
524% CacheInfo *source_info,ExceptionInfo *exception)
525%
526% A description of each parameter follows:
527%
528% o cache_info: the pixel cache.
529%
530% o source_info: the source pixel cache.
531%
532% o exception: return any errors or warnings in this structure.
533%
534*/
535
536static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
537{
538 int
539 status;
540
cristy5ee247a2010-02-12 15:42:34 +0000541 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000542 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000543 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000544 {
545 status=close(cache_info->file);
546 cache_info->file=(-1);
547 RelinquishMagickResource(FileResource,1);
548 }
cristyf84a1932010-01-03 18:00:18 +0000549 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000550 return(status == -1 ? MagickFalse : MagickTrue);
551}
552
cristy3ed852e2009-09-05 21:47:34 +0000553static inline MagickSizeType MagickMax(const MagickSizeType x,
554 const MagickSizeType y)
555{
556 if (x > y)
557 return(x);
558 return(y);
559}
560
561static inline MagickSizeType MagickMin(const MagickSizeType x,
562 const MagickSizeType y)
563{
564 if (x < y)
565 return(x);
566 return(y);
567}
568
569static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
570 const MapMode mode)
571{
572 int
573 file;
574
575 /*
576 Open pixel cache on disk.
577 */
cristyf84a1932010-01-03 18:00:18 +0000578 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000579 if (cache_info->file != -1)
580 {
cristyf84a1932010-01-03 18:00:18 +0000581 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000582 return(MagickTrue); /* cache already open */
583 }
cristy3ed852e2009-09-05 21:47:34 +0000584 if (*cache_info->cache_filename == '\0')
585 file=AcquireUniqueFileResource(cache_info->cache_filename);
586 else
587 switch (mode)
588 {
589 case ReadMode:
590 {
cristy18c6c272011-09-23 14:40:37 +0000591 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000592 break;
593 }
594 case WriteMode:
595 {
cristy18c6c272011-09-23 14:40:37 +0000596 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
597 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000598 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000599 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000600 break;
601 }
602 case IOMode:
603 default:
604 {
cristy18c6c272011-09-23 14:40:37 +0000605 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000606 O_EXCL,S_MODE);
607 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000608 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000609 break;
610 }
611 }
612 if (file == -1)
613 {
cristyf84a1932010-01-03 18:00:18 +0000614 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000615 return(MagickFalse);
616 }
617 (void) AcquireMagickResource(FileResource,1);
618 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000619 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000620 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000621 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000622 return(MagickTrue);
623}
624
625static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
626 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000627 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000628{
629 register MagickOffsetType
630 i;
631
632 ssize_t
633 count;
634
cristy08a88202010-03-04 19:18:05 +0000635 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000636#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000637 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000638 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000639 {
cristyf84a1932010-01-03 18:00:18 +0000640 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000641 return((MagickOffsetType) -1);
642 }
643#endif
644 count=0;
645 for (i=0; i < (MagickOffsetType) length; i+=count)
646 {
647#if !defined(MAGICKCORE_HAVE_PREAD)
648 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
649 (MagickSizeType) SSIZE_MAX));
650#else
651 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000652 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000653#endif
654 if (count > 0)
655 continue;
656 count=0;
657 if (errno != EINTR)
658 {
659 i=(-1);
660 break;
661 }
662 }
663#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000664 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000665#endif
666 return(i);
667}
668
669static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
670 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000671 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000672{
673 register MagickOffsetType
674 i;
675
676 ssize_t
677 count;
678
cristy08a88202010-03-04 19:18:05 +0000679 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000680#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000681 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000682 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000683 {
cristyf84a1932010-01-03 18:00:18 +0000684 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000685 return((MagickOffsetType) -1);
686 }
687#endif
688 count=0;
689 for (i=0; i < (MagickOffsetType) length; i+=count)
690 {
691#if !defined(MAGICKCORE_HAVE_PWRITE)
692 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
693 (MagickSizeType) SSIZE_MAX));
694#else
695 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000696 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000697#endif
698 if (count > 0)
699 continue;
700 count=0;
701 if (errno != EINTR)
702 {
703 i=(-1);
704 break;
705 }
706 }
707#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000708 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000709#endif
710 return(i);
711}
712
cristy4c08aed2011-07-01 19:47:50 +0000713static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000714 CacheInfo *cache_info,ExceptionInfo *exception)
715{
716 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000717 count;
cristy3ed852e2009-09-05 21:47:34 +0000718
cristy4c08aed2011-07-01 19:47:50 +0000719 register MagickOffsetType
720 i;
cristye076a6e2010-08-15 19:59:43 +0000721
cristybb503372010-05-27 20:51:26 +0000722 size_t
cristy4c08aed2011-07-01 19:47:50 +0000723 length;
cristy3ed852e2009-09-05 21:47:34 +0000724
cristy4c08aed2011-07-01 19:47:50 +0000725 unsigned char
726 *blob;
727
728 /*
729 Clone pixel cache (both caches on disk).
730 */
cristy3ed852e2009-09-05 21:47:34 +0000731 if (cache_info->debug != MagickFalse)
732 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000733 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000734 sizeof(*blob));
735 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000736 {
cristy4c08aed2011-07-01 19:47:50 +0000737 (void) ThrowMagickException(exception,GetMagickModule(),
738 ResourceLimitError,"MemoryAllocationFailed","`%s'",
739 cache_info->filename);
740 return(MagickFalse);
741 }
cristy3dedf062011-07-02 14:07:40 +0000742 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000743 {
744 blob=(unsigned char *) RelinquishMagickMemory(blob);
745 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
746 cache_info->cache_filename);
747 return(MagickFalse);
748 }
cristy3dedf062011-07-02 14:07:40 +0000749 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000750 {
751 (void) ClosePixelCacheOnDisk(cache_info);
752 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000753 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
754 clone_info->cache_filename);
755 return(MagickFalse);
756 }
cristy4c08aed2011-07-01 19:47:50 +0000757 count=0;
758 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000759 {
cristy4c08aed2011-07-01 19:47:50 +0000760 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
761 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
762 blob);
763 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000764 {
cristy4c08aed2011-07-01 19:47:50 +0000765 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
766 cache_info->cache_filename);
767 break;
cristy3ed852e2009-09-05 21:47:34 +0000768 }
cristy4c08aed2011-07-01 19:47:50 +0000769 length=(size_t) count;
770 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
771 if ((MagickSizeType) count != length)
772 {
773 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
774 clone_info->cache_filename);
775 break;
776 }
777 }
778 (void) ClosePixelCacheOnDisk(clone_info);
779 (void) ClosePixelCacheOnDisk(cache_info);
780 blob=(unsigned char *) RelinquishMagickMemory(blob);
781 if (i < (MagickOffsetType) cache_info->length)
782 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000783 return(MagickTrue);
784}
785
cristyfd24a062012-01-02 14:46:34 +0000786static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000787 CacheInfo *cache_info,ExceptionInfo *exception)
788{
789 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000790 count;
cristy3ed852e2009-09-05 21:47:34 +0000791
cristy4c08aed2011-07-01 19:47:50 +0000792 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000793 {
cristy3ed852e2009-09-05 21:47:34 +0000794 /*
cristy4c08aed2011-07-01 19:47:50 +0000795 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000796 */
cristy4c08aed2011-07-01 19:47:50 +0000797 if (cache_info->debug != MagickFalse)
798 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
799 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
800 cache_info->length);
801 return(MagickTrue);
802 }
803 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
804 {
805 /*
806 Clone pixel cache (one cache on disk, one in memory).
807 */
808 if (cache_info->debug != MagickFalse)
809 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
810 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000811 {
cristy4c08aed2011-07-01 19:47:50 +0000812 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000813 cache_info->cache_filename);
814 return(MagickFalse);
815 }
cristy4c08aed2011-07-01 19:47:50 +0000816 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
817 cache_info->length,(unsigned char *) clone_info->pixels);
818 (void) ClosePixelCacheOnDisk(cache_info);
819 if ((MagickSizeType) count != cache_info->length)
820 {
821 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
822 cache_info->cache_filename);
823 return(MagickFalse);
824 }
825 return(MagickTrue);
826 }
827 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
828 {
829 /*
830 Clone pixel cache (one cache on disk, one in memory).
831 */
832 if (clone_info->debug != MagickFalse)
833 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
834 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
835 {
836 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
837 clone_info->cache_filename);
838 return(MagickFalse);
839 }
840 count=WritePixelCacheRegion(clone_info,clone_info->offset,
841 clone_info->length,(unsigned char *) cache_info->pixels);
842 (void) ClosePixelCacheOnDisk(clone_info);
843 if ((MagickSizeType) count != clone_info->length)
844 {
845 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
846 clone_info->cache_filename);
847 return(MagickFalse);
848 }
849 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000850 }
851 /*
cristy4c08aed2011-07-01 19:47:50 +0000852 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000853 */
cristy4c08aed2011-07-01 19:47:50 +0000854 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000855}
856
cristyfd24a062012-01-02 14:46:34 +0000857static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000858 CacheInfo *cache_info,ExceptionInfo *exception)
859{
cristy4c08aed2011-07-01 19:47:50 +0000860 MagickBooleanType
861 status;
cristy3ed852e2009-09-05 21:47:34 +0000862
cristy4c08aed2011-07-01 19:47:50 +0000863 MagickOffsetType
864 cache_offset,
865 clone_offset,
866 count;
867
868 register ssize_t
869 x;
870
cristyfd24a062012-01-02 14:46:34 +0000871 register unsigned char
872 *p;
873
cristy4c08aed2011-07-01 19:47:50 +0000874 size_t
cristy3ed852e2009-09-05 21:47:34 +0000875 length;
876
cristy4c08aed2011-07-01 19:47:50 +0000877 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000878 y;
879
cristy4c08aed2011-07-01 19:47:50 +0000880 unsigned char
881 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000882
cristy4c08aed2011-07-01 19:47:50 +0000883 /*
884 Clone pixel cache (unoptimized).
885 */
cristy3ed852e2009-09-05 21:47:34 +0000886 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000887 {
cristy4c08aed2011-07-01 19:47:50 +0000888 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
889 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
890 else
891 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
892 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
893 else
894 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
895 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
896 else
897 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
898 }
cristyed231572011-07-14 02:18:59 +0000899 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
900 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000901 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000902 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000903 if (blob == (unsigned char *) NULL)
904 {
905 (void) ThrowMagickException(exception,GetMagickModule(),
906 ResourceLimitError,"MemoryAllocationFailed","`%s'",
907 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000908 return(MagickFalse);
909 }
cristy4c08aed2011-07-01 19:47:50 +0000910 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
911 cache_offset=0;
912 clone_offset=0;
913 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000914 {
cristy4c08aed2011-07-01 19:47:50 +0000915 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000916 {
cristy4c08aed2011-07-01 19:47:50 +0000917 blob=(unsigned char *) RelinquishMagickMemory(blob);
918 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000919 cache_info->cache_filename);
920 return(MagickFalse);
921 }
cristy4c08aed2011-07-01 19:47:50 +0000922 cache_offset=cache_info->offset;
923 }
924 if (clone_info->type == DiskCache)
925 {
cristy3dedf062011-07-02 14:07:40 +0000926 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000927 {
cristy4c08aed2011-07-01 19:47:50 +0000928 blob=(unsigned char *) RelinquishMagickMemory(blob);
929 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
930 clone_info->cache_filename);
931 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000932 }
cristy4c08aed2011-07-01 19:47:50 +0000933 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000934 }
935 /*
cristy4c08aed2011-07-01 19:47:50 +0000936 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000937 */
cristy4c08aed2011-07-01 19:47:50 +0000938 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000939 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000940 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000941 {
cristy4c08aed2011-07-01 19:47:50 +0000942 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000943 {
cristy9e0719b2011-12-29 03:45:45 +0000944 register ssize_t
945 i;
946
cristy3ed852e2009-09-05 21:47:34 +0000947 /*
cristy4c08aed2011-07-01 19:47:50 +0000948 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000949 */
cristyed231572011-07-14 02:18:59 +0000950 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000951 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000952 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000953 else
954 {
cristyfd24a062012-01-02 14:46:34 +0000955 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000956 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000957 {
cristy4c08aed2011-07-01 19:47:50 +0000958 status=MagickFalse;
959 break;
cristy3ed852e2009-09-05 21:47:34 +0000960 }
961 }
cristy4c08aed2011-07-01 19:47:50 +0000962 cache_offset+=length;
963 if ((y < (ssize_t) clone_info->rows) &&
964 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000965 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
cristy9e0719b2011-12-29 03:45:45 +0000967 PixelChannel
968 channel;
969
970 PixelTrait
971 traits;
972
973 ssize_t
974 offset;
975
cristy4c08aed2011-07-01 19:47:50 +0000976 /*
cristy3b8fe922011-12-29 18:56:23 +0000977 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000978 */
cristy9e0719b2011-12-29 03:45:45 +0000979 channel=clone_info->channel_map[i].channel;
980 traits=cache_info->channel_map[channel].traits;
981 if (traits == UndefinedPixelTrait)
982 {
cristy0f4425e2011-12-31 20:33:02 +0000983 clone_offset+=sizeof(Quantum);
984 continue;
cristy9e0719b2011-12-29 03:45:45 +0000985 }
cristy0f4425e2011-12-31 20:33:02 +0000986 offset=cache_info->channel_map[channel].offset;
987 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000988 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
989 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000990 else
991 {
cristy0f4425e2011-12-31 20:33:02 +0000992 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000993 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000994 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000995 {
cristy0f4425e2011-12-31 20:33:02 +0000996 status=MagickFalse;
997 break;
cristy4c08aed2011-07-01 19:47:50 +0000998 }
999 }
cristy9e0719b2011-12-29 03:45:45 +00001000 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001001 }
1002 }
cristyed231572011-07-14 02:18:59 +00001003 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001004 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1005 for ( ; x < (ssize_t) clone_info->columns; x++)
1006 {
1007 /*
cristy9e0719b2011-12-29 03:45:45 +00001008 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001009 */
1010 if (clone_info->type != DiskCache)
1011 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1012 length);
1013 else
1014 {
1015 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1016 if ((MagickSizeType) count != length)
1017 {
1018 status=MagickFalse;
1019 break;
1020 }
1021 }
1022 clone_offset+=length;
1023 }
1024 }
cristyed231572011-07-14 02:18:59 +00001025 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001026 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1027 for ( ; y < (ssize_t) clone_info->rows; y++)
1028 {
1029 /*
cristy9e0719b2011-12-29 03:45:45 +00001030 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001031 */
1032 for (x=0; x < (ssize_t) clone_info->columns; x++)
1033 {
1034 if (clone_info->type != DiskCache)
1035 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1036 length);
1037 else
1038 {
1039 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1040 if ((MagickSizeType) count != length)
1041 {
1042 status=MagickFalse;
1043 break;
1044 }
1045 }
1046 clone_offset+=length;
1047 }
1048 }
cristy9e0719b2011-12-29 03:45:45 +00001049 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001050 (clone_info->metacontent_extent != 0))
1051 {
1052 /*
1053 Clone metacontent.
1054 */
1055 for (y=0; y < (ssize_t) cache_info->rows; y++)
1056 {
1057 for (x=0; x < (ssize_t) cache_info->columns; x++)
1058 {
1059 /*
1060 Read a set of metacontent.
1061 */
1062 length=cache_info->metacontent_extent;
1063 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +00001064 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +00001065 else
1066 {
cristyfd24a062012-01-02 14:46:34 +00001067 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001068 if ((MagickSizeType) count != length)
1069 {
1070 status=MagickFalse;
1071 break;
1072 }
1073 }
1074 cache_offset+=length;
1075 if ((y < (ssize_t) clone_info->rows) &&
1076 (x < (ssize_t) clone_info->columns))
1077 {
1078 /*
1079 Write a set of metacontent.
1080 */
1081 length=clone_info->metacontent_extent;
1082 if (clone_info->type != DiskCache)
1083 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +00001084 p,length);
cristy4c08aed2011-07-01 19:47:50 +00001085 else
1086 {
cristyfd24a062012-01-02 14:46:34 +00001087 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001088 if ((MagickSizeType) count != length)
1089 {
1090 status=MagickFalse;
1091 break;
1092 }
1093 }
1094 clone_offset+=length;
1095 }
1096 }
1097 length=clone_info->metacontent_extent;
1098 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1099 for ( ; x < (ssize_t) clone_info->columns; x++)
1100 {
1101 /*
cristy9e0719b2011-12-29 03:45:45 +00001102 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001103 */
1104 if (clone_info->type != DiskCache)
1105 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1106 blob,length);
1107 else
1108 {
cristy208b1002011-08-07 18:51:50 +00001109 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001110 if ((MagickSizeType) count != length)
1111 {
1112 status=MagickFalse;
1113 break;
1114 }
1115 }
1116 clone_offset+=length;
1117 }
1118 }
1119 length=clone_info->metacontent_extent;
1120 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1121 for ( ; y < (ssize_t) clone_info->rows; y++)
1122 {
1123 /*
cristy9e0719b2011-12-29 03:45:45 +00001124 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001125 */
1126 for (x=0; x < (ssize_t) clone_info->columns; x++)
1127 {
1128 if (clone_info->type != DiskCache)
1129 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1130 blob,length);
1131 else
1132 {
1133 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1134 if ((MagickSizeType) count != length)
1135 {
1136 status=MagickFalse;
1137 break;
1138 }
1139 }
1140 clone_offset+=length;
1141 }
1142 }
1143 }
1144 if (clone_info->type == DiskCache)
1145 (void) ClosePixelCacheOnDisk(clone_info);
1146 if (cache_info->type == DiskCache)
1147 (void) ClosePixelCacheOnDisk(cache_info);
1148 blob=(unsigned char *) RelinquishMagickMemory(blob);
1149 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001150}
1151
1152static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1153 CacheInfo *cache_info,ExceptionInfo *exception)
1154{
cristy3dfccb22011-12-28 21:47:20 +00001155 PixelChannelMap
1156 *p,
1157 *q;
1158
cristy5a7fbfb2010-11-06 16:10:59 +00001159 if (cache_info->type == PingCache)
1160 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001161 p=cache_info->channel_map;
1162 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001163 if ((cache_info->columns == clone_info->columns) &&
1164 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001165 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001166 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001167 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001168 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1169 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001170}
1171
1172/*
1173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1174% %
1175% %
1176% %
1177+ C l o n e P i x e l C a c h e M e t h o d s %
1178% %
1179% %
1180% %
1181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1182%
1183% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1184% another.
1185%
1186% The format of the ClonePixelCacheMethods() method is:
1187%
1188% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1189%
1190% A description of each parameter follows:
1191%
1192% o clone: Specifies a pointer to a Cache structure.
1193%
1194% o cache: the pixel cache.
1195%
1196*/
cristya6577ff2011-09-02 19:54:26 +00001197MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001198{
1199 CacheInfo
1200 *cache_info,
1201 *source_info;
1202
1203 assert(clone != (Cache) NULL);
1204 source_info=(CacheInfo *) clone;
1205 assert(source_info->signature == MagickSignature);
1206 if (source_info->debug != MagickFalse)
1207 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1208 source_info->filename);
1209 assert(cache != (Cache) NULL);
1210 cache_info=(CacheInfo *) cache;
1211 assert(cache_info->signature == MagickSignature);
1212 source_info->methods=cache_info->methods;
1213}
1214
1215/*
1216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1217% %
1218% %
1219% %
1220+ D e s t r o y I m a g e P i x e l C a c h e %
1221% %
1222% %
1223% %
1224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1225%
1226% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1227%
1228% The format of the DestroyImagePixelCache() method is:
1229%
1230% void DestroyImagePixelCache(Image *image)
1231%
1232% A description of each parameter follows:
1233%
1234% o image: the image.
1235%
1236*/
1237static void DestroyImagePixelCache(Image *image)
1238{
1239 assert(image != (Image *) NULL);
1240 assert(image->signature == MagickSignature);
1241 if (image->debug != MagickFalse)
1242 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1243 if (image->cache == (void *) NULL)
1244 return;
1245 image->cache=DestroyPixelCache(image->cache);
1246}
1247
1248/*
1249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1250% %
1251% %
1252% %
1253+ D e s t r o y I m a g e P i x e l s %
1254% %
1255% %
1256% %
1257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258%
1259% DestroyImagePixels() deallocates memory associated with the pixel cache.
1260%
1261% The format of the DestroyImagePixels() method is:
1262%
1263% void DestroyImagePixels(Image *image)
1264%
1265% A description of each parameter follows:
1266%
1267% o image: the image.
1268%
1269*/
1270MagickExport void DestroyImagePixels(Image *image)
1271{
1272 CacheInfo
1273 *cache_info;
1274
1275 assert(image != (const Image *) NULL);
1276 assert(image->signature == MagickSignature);
1277 if (image->debug != MagickFalse)
1278 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1279 assert(image->cache != (Cache) NULL);
1280 cache_info=(CacheInfo *) image->cache;
1281 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001282 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1283 {
1284 cache_info->methods.destroy_pixel_handler(image);
1285 return;
1286 }
cristy2036f5c2010-09-19 21:18:17 +00001287 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001288}
1289
1290/*
1291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1292% %
1293% %
1294% %
1295+ D e s t r o y P i x e l C a c h e %
1296% %
1297% %
1298% %
1299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1300%
1301% DestroyPixelCache() deallocates memory associated with the pixel cache.
1302%
1303% The format of the DestroyPixelCache() method is:
1304%
1305% Cache DestroyPixelCache(Cache cache)
1306%
1307% A description of each parameter follows:
1308%
1309% o cache: the pixel cache.
1310%
1311*/
1312
1313static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1314{
1315 switch (cache_info->type)
1316 {
1317 case MemoryCache:
1318 {
1319 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001320 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001321 cache_info->pixels);
1322 else
cristy4c08aed2011-07-01 19:47:50 +00001323 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001324 (size_t) cache_info->length);
1325 RelinquishMagickResource(MemoryResource,cache_info->length);
1326 break;
1327 }
1328 case MapCache:
1329 {
cristy4c08aed2011-07-01 19:47:50 +00001330 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001331 cache_info->length);
1332 RelinquishMagickResource(MapResource,cache_info->length);
1333 }
1334 case DiskCache:
1335 {
1336 if (cache_info->file != -1)
1337 (void) ClosePixelCacheOnDisk(cache_info);
1338 RelinquishMagickResource(DiskResource,cache_info->length);
1339 break;
1340 }
1341 default:
1342 break;
1343 }
1344 cache_info->type=UndefinedCache;
1345 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001346 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001347}
1348
cristya6577ff2011-09-02 19:54:26 +00001349MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001350{
1351 CacheInfo
1352 *cache_info;
1353
cristy3ed852e2009-09-05 21:47:34 +00001354 assert(cache != (Cache) NULL);
1355 cache_info=(CacheInfo *) cache;
1356 assert(cache_info->signature == MagickSignature);
1357 if (cache_info->debug != MagickFalse)
1358 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1359 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001360 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001361 cache_info->reference_count--;
1362 if (cache_info->reference_count != 0)
1363 {
cristyf84a1932010-01-03 18:00:18 +00001364 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001365 return((Cache) NULL);
1366 }
cristyf84a1932010-01-03 18:00:18 +00001367 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001368 if (cache_info->debug != MagickFalse)
1369 {
1370 char
1371 message[MaxTextExtent];
1372
cristyb51dff52011-05-19 16:55:47 +00001373 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001374 cache_info->filename);
1375 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1376 }
cristyc2e1bdd2009-09-10 23:43:34 +00001377 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1378 (cache_info->type != DiskCache)))
1379 RelinquishPixelCachePixels(cache_info);
1380 else
1381 {
1382 RelinquishPixelCachePixels(cache_info);
1383 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1384 }
cristy3ed852e2009-09-05 21:47:34 +00001385 *cache_info->cache_filename='\0';
1386 if (cache_info->nexus_info != (NexusInfo **) NULL)
1387 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1388 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001389 if (cache_info->random_info != (RandomInfo *) NULL)
1390 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001391 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1392 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1393 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1394 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001395 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001396 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001397 cache=(Cache) NULL;
1398 return(cache);
1399}
1400
1401/*
1402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403% %
1404% %
1405% %
1406+ D e s t r o y P i x e l C a c h e N e x u s %
1407% %
1408% %
1409% %
1410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411%
1412% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1413%
1414% The format of the DestroyPixelCacheNexus() method is:
1415%
1416% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001417% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001418%
1419% A description of each parameter follows:
1420%
1421% o nexus_info: the nexus to destroy.
1422%
1423% o number_threads: the number of nexus threads.
1424%
1425*/
1426
1427static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1428{
1429 if (nexus_info->mapped == MagickFalse)
cristy7dc8ac52012-01-10 20:14:52 +00001430 (void) RelinquishAlignedMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001431 else
1432 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001433 nexus_info->cache=(Quantum *) NULL;
1434 nexus_info->pixels=(Quantum *) NULL;
1435 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001436 nexus_info->length=0;
1437 nexus_info->mapped=MagickFalse;
1438}
1439
cristya6577ff2011-09-02 19:54:26 +00001440MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001441 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001442{
cristybb503372010-05-27 20:51:26 +00001443 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001444 i;
1445
1446 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001447 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001448 {
cristy4c08aed2011-07-01 19:47:50 +00001449 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001450 RelinquishCacheNexusPixels(nexus_info[i]);
1451 nexus_info[i]->signature=(~MagickSignature);
cristy7dc8ac52012-01-10 20:14:52 +00001452 nexus_info[i]=(NexusInfo *) RelinquishMagickMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001453 }
cristyb41ee102010-10-04 16:46:15 +00001454 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001455 return(nexus_info);
1456}
1457
1458/*
1459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1460% %
1461% %
1462% %
cristy4c08aed2011-07-01 19:47:50 +00001463% 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 +00001464% %
1465% %
1466% %
1467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1468%
cristy4c08aed2011-07-01 19:47:50 +00001469% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1470% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1471% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001472%
cristy4c08aed2011-07-01 19:47:50 +00001473% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001474%
cristy4c08aed2011-07-01 19:47:50 +00001475% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001476%
1477% A description of each parameter follows:
1478%
1479% o image: the image.
1480%
1481*/
cristy4c08aed2011-07-01 19:47:50 +00001482MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001483{
1484 CacheInfo
1485 *cache_info;
1486
cristy5c9e6f22010-09-17 17:31:01 +00001487 const int
1488 id = GetOpenMPThreadId();
1489
cristy4c08aed2011-07-01 19:47:50 +00001490 void
1491 *metacontent;
1492
cristye7cc7cf2010-09-21 13:26:47 +00001493 assert(image != (const Image *) NULL);
1494 assert(image->signature == MagickSignature);
1495 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001496 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001497 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001498 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1499 (GetAuthenticMetacontentFromHandler) NULL)
1500 {
1501 metacontent=cache_info->methods.
1502 get_authentic_metacontent_from_handler(image);
1503 return(metacontent);
1504 }
cristy6ebe97c2010-07-03 01:17:28 +00001505 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001506 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1507 cache_info->nexus_info[id]);
1508 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001509}
1510
1511/*
1512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1513% %
1514% %
1515% %
cristy4c08aed2011-07-01 19:47:50 +00001516+ 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 +00001517% %
1518% %
1519% %
1520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1521%
cristy4c08aed2011-07-01 19:47:50 +00001522% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1523% with the last call to QueueAuthenticPixelsCache() or
1524% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001525%
cristy4c08aed2011-07-01 19:47:50 +00001526% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001527%
cristy4c08aed2011-07-01 19:47:50 +00001528% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001529%
1530% A description of each parameter follows:
1531%
1532% o image: the image.
1533%
1534*/
cristy4c08aed2011-07-01 19:47:50 +00001535static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001536{
1537 CacheInfo
1538 *cache_info;
1539
cristy2036f5c2010-09-19 21:18:17 +00001540 const int
1541 id = GetOpenMPThreadId();
1542
cristy4c08aed2011-07-01 19:47:50 +00001543 void
1544 *metacontent;
1545
cristy3ed852e2009-09-05 21:47:34 +00001546 assert(image != (const Image *) NULL);
1547 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001548 assert(image->cache != (Cache) NULL);
1549 cache_info=(CacheInfo *) image->cache;
1550 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001551 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001552 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1553 cache_info->nexus_info[id]);
1554 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001555}
1556
1557/*
1558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1559% %
1560% %
1561% %
1562+ 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 %
1563% %
1564% %
1565% %
1566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1567%
1568% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1569% disk pixel cache as defined by the geometry parameters. A pointer to the
1570% pixels is returned if the pixels are transferred, otherwise a NULL is
1571% returned.
1572%
1573% The format of the GetAuthenticPixelCacheNexus() method is:
1574%
cristy4c08aed2011-07-01 19:47:50 +00001575% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001576% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001577% NexusInfo *nexus_info,ExceptionInfo *exception)
1578%
1579% A description of each parameter follows:
1580%
1581% o image: the image.
1582%
1583% o x,y,columns,rows: These values define the perimeter of a region of
1584% pixels.
1585%
1586% o nexus_info: the cache nexus to return.
1587%
1588% o exception: return any errors or warnings in this structure.
1589%
1590*/
1591
cristy4c08aed2011-07-01 19:47:50 +00001592static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001593 NexusInfo *nexus_info)
1594{
cristy4c08aed2011-07-01 19:47:50 +00001595 MagickBooleanType
1596 status;
1597
cristy3ed852e2009-09-05 21:47:34 +00001598 MagickOffsetType
1599 offset;
1600
cristy73724512010-04-12 14:43:14 +00001601 if (cache_info->type == PingCache)
1602 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001603 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1604 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001605 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001606 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001607 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001608}
1609
cristya6577ff2011-09-02 19:54:26 +00001610MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001611 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001612 NexusInfo *nexus_info,ExceptionInfo *exception)
1613{
1614 CacheInfo
1615 *cache_info;
1616
cristy4c08aed2011-07-01 19:47:50 +00001617 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001618 *q;
cristy3ed852e2009-09-05 21:47:34 +00001619
1620 /*
1621 Transfer pixels from the cache.
1622 */
1623 assert(image != (Image *) NULL);
1624 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001625 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1626 exception);
cristyacd2ed22011-08-30 01:44:23 +00001627 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001628 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001629 cache_info=(CacheInfo *) image->cache;
1630 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001631 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001632 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001633 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001634 return((Quantum *) NULL);
1635 if (cache_info->metacontent_extent != 0)
1636 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1637 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001638 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001639}
1640
1641/*
1642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1643% %
1644% %
1645% %
1646+ 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 %
1647% %
1648% %
1649% %
1650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1651%
1652% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1653% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1654%
1655% The format of the GetAuthenticPixelsFromCache() method is:
1656%
cristy4c08aed2011-07-01 19:47:50 +00001657% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001658%
1659% A description of each parameter follows:
1660%
1661% o image: the image.
1662%
1663*/
cristy4c08aed2011-07-01 19:47:50 +00001664static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001665{
1666 CacheInfo
1667 *cache_info;
1668
cristy5c9e6f22010-09-17 17:31:01 +00001669 const int
1670 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001671
cristye7cc7cf2010-09-21 13:26:47 +00001672 assert(image != (const Image *) NULL);
1673 assert(image->signature == MagickSignature);
1674 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001675 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001676 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001677 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001678 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001679}
1680
1681/*
1682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683% %
1684% %
1685% %
1686% G e t A u t h e n t i c P i x e l Q u e u e %
1687% %
1688% %
1689% %
1690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1691%
cristy4c08aed2011-07-01 19:47:50 +00001692% GetAuthenticPixelQueue() returns the authentic pixels associated
1693% corresponding with the last call to QueueAuthenticPixels() or
1694% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001695%
1696% The format of the GetAuthenticPixelQueue() method is:
1697%
cristy4c08aed2011-07-01 19:47:50 +00001698% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001699%
1700% A description of each parameter follows:
1701%
1702% o image: the image.
1703%
1704*/
cristy4c08aed2011-07-01 19:47:50 +00001705MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001706{
1707 CacheInfo
1708 *cache_info;
1709
cristy2036f5c2010-09-19 21:18:17 +00001710 const int
1711 id = GetOpenMPThreadId();
1712
cristy3ed852e2009-09-05 21:47:34 +00001713 assert(image != (const Image *) NULL);
1714 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001715 assert(image->cache != (Cache) NULL);
1716 cache_info=(CacheInfo *) image->cache;
1717 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001718 if (cache_info->methods.get_authentic_pixels_from_handler !=
1719 (GetAuthenticPixelsFromHandler) NULL)
1720 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001721 assert(id < (int) cache_info->number_threads);
1722 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001723}
1724
1725/*
1726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1727% %
1728% %
1729% %
1730% G e t A u t h e n t i c P i x e l s %
1731% %
1732% %
cristy4c08aed2011-07-01 19:47:50 +00001733% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001734%
1735% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001736% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001737% representing the region is returned, otherwise NULL is returned.
1738%
1739% The returned pointer may point to a temporary working copy of the pixels
1740% or it may point to the original pixels in memory. Performance is maximized
1741% if the selected region is part of one row, or one or more full rows, since
1742% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001743% if the image is in memory, or in a memory-mapped file. The returned pointer
1744% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001745%
1746% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001747% Quantum. If the image has corresponding metacontent,call
1748% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1749% meta-content corresponding to the region. Once the Quantum array has
1750% been updated, the changes must be saved back to the underlying image using
1751% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001752%
1753% The format of the GetAuthenticPixels() method is:
1754%
cristy4c08aed2011-07-01 19:47:50 +00001755% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001756% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001757% ExceptionInfo *exception)
1758%
1759% A description of each parameter follows:
1760%
1761% o image: the image.
1762%
1763% o x,y,columns,rows: These values define the perimeter of a region of
1764% pixels.
1765%
1766% o exception: return any errors or warnings in this structure.
1767%
1768*/
cristy4c08aed2011-07-01 19:47:50 +00001769MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001770 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001771 ExceptionInfo *exception)
1772{
1773 CacheInfo
1774 *cache_info;
1775
cristy2036f5c2010-09-19 21:18:17 +00001776 const int
1777 id = GetOpenMPThreadId();
1778
cristy4c08aed2011-07-01 19:47:50 +00001779 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001780 *q;
cristy4c08aed2011-07-01 19:47:50 +00001781
cristy3ed852e2009-09-05 21:47:34 +00001782 assert(image != (Image *) NULL);
1783 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001784 assert(image->cache != (Cache) NULL);
1785 cache_info=(CacheInfo *) image->cache;
1786 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001787 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001788 (GetAuthenticPixelsHandler) NULL)
1789 {
cristyacd2ed22011-08-30 01:44:23 +00001790 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1791 exception);
1792 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001793 }
cristy2036f5c2010-09-19 21:18:17 +00001794 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001795 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001796 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001797 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001798}
1799
1800/*
1801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802% %
1803% %
1804% %
1805+ G e t A u t h e n t i c P i x e l s C a c h e %
1806% %
1807% %
1808% %
1809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1810%
1811% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1812% as defined by the geometry parameters. A pointer to the pixels is returned
1813% if the pixels are transferred, otherwise a NULL is returned.
1814%
1815% The format of the GetAuthenticPixelsCache() method is:
1816%
cristy4c08aed2011-07-01 19:47:50 +00001817% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001818% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001819% ExceptionInfo *exception)
1820%
1821% A description of each parameter follows:
1822%
1823% o image: the image.
1824%
1825% o x,y,columns,rows: These values define the perimeter of a region of
1826% pixels.
1827%
1828% o exception: return any errors or warnings in this structure.
1829%
1830*/
cristy4c08aed2011-07-01 19:47:50 +00001831static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001832 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001833 ExceptionInfo *exception)
1834{
1835 CacheInfo
1836 *cache_info;
1837
cristy5c9e6f22010-09-17 17:31:01 +00001838 const int
1839 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001840
cristy4c08aed2011-07-01 19:47:50 +00001841 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001842 *q;
cristy4c08aed2011-07-01 19:47:50 +00001843
cristye7cc7cf2010-09-21 13:26:47 +00001844 assert(image != (const Image *) NULL);
1845 assert(image->signature == MagickSignature);
1846 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001847 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001848 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001849 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001850 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001851 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001852 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001853 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001854 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001855}
1856
1857/*
1858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1859% %
1860% %
1861% %
1862+ G e t I m a g e E x t e n t %
1863% %
1864% %
1865% %
1866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1867%
cristy4c08aed2011-07-01 19:47:50 +00001868% GetImageExtent() returns the extent of the pixels associated corresponding
1869% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001870%
1871% The format of the GetImageExtent() method is:
1872%
1873% MagickSizeType GetImageExtent(const Image *image)
1874%
1875% A description of each parameter follows:
1876%
1877% o image: the image.
1878%
1879*/
1880MagickExport MagickSizeType GetImageExtent(const Image *image)
1881{
1882 CacheInfo
1883 *cache_info;
1884
cristy5c9e6f22010-09-17 17:31:01 +00001885 const int
1886 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001887
cristy3ed852e2009-09-05 21:47:34 +00001888 assert(image != (Image *) NULL);
1889 assert(image->signature == MagickSignature);
1890 if (image->debug != MagickFalse)
1891 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1892 assert(image->cache != (Cache) NULL);
1893 cache_info=(CacheInfo *) image->cache;
1894 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001895 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001896 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001897}
1898
1899/*
1900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1901% %
1902% %
1903% %
1904+ G e t I m a g e P i x e l C a c h e %
1905% %
1906% %
1907% %
1908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1909%
1910% GetImagePixelCache() ensures that there is only a single reference to the
1911% pixel cache to be modified, updating the provided cache pointer to point to
1912% a clone of the original pixel cache if necessary.
1913%
1914% The format of the GetImagePixelCache method is:
1915%
1916% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1917% ExceptionInfo *exception)
1918%
1919% A description of each parameter follows:
1920%
1921% o image: the image.
1922%
1923% o clone: any value other than MagickFalse clones the cache pixels.
1924%
1925% o exception: return any errors or warnings in this structure.
1926%
1927*/
cristyaf894d72011-08-06 23:03:10 +00001928
cristy3ed852e2009-09-05 21:47:34 +00001929static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1930{
1931 CacheInfo
1932 *cache_info;
1933
cristy9e0719b2011-12-29 03:45:45 +00001934 PixelChannelMap
1935 *p,
1936 *q;
1937
cristy3ed852e2009-09-05 21:47:34 +00001938 /*
1939 Does the image match the pixel cache morphology?
1940 */
1941 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001942 p=image->channel_map;
1943 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001944 if ((image->storage_class != cache_info->storage_class) ||
1945 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001946 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00001947 (image->columns != cache_info->columns) ||
1948 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001949 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001950 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001951 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001952 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1953 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1954 return(MagickFalse);
1955 return(MagickTrue);
1956}
1957
cristycd01fae2011-08-06 23:52:42 +00001958static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1959 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001960{
1961 CacheInfo
1962 *cache_info;
1963
cristy3ed852e2009-09-05 21:47:34 +00001964 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001965 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001966 status;
1967
cristy50a10922010-02-15 18:35:25 +00001968 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001969 cpu_throttle = 0,
1970 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001971 time_limit = 0;
1972
cristy1ea34962010-07-01 19:49:21 +00001973 static time_t
cristy208b1002011-08-07 18:51:50 +00001974 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001975
cristyc4f9f132010-03-04 18:50:01 +00001976 status=MagickTrue;
1977 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001978 if (cpu_throttle == 0)
1979 {
1980 char
1981 *limit;
1982
1983 /*
1984 Set CPU throttle in milleseconds.
1985 */
1986 cpu_throttle=MagickResourceInfinity;
1987 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1988 if (limit == (char *) NULL)
1989 limit=GetPolicyValue("throttle");
1990 if (limit != (char *) NULL)
1991 {
1992 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1993 limit=DestroyString(limit);
1994 }
1995 }
1996 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1997 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001998 if (time_limit == 0)
1999 {
cristy6ebe97c2010-07-03 01:17:28 +00002000 /*
2001 Set the exire time in seconds.
2002 */
cristy1ea34962010-07-01 19:49:21 +00002003 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002004 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002005 }
2006 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002007 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002008 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002009 assert(image->cache != (Cache) NULL);
2010 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002011 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002012 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002013 {
cristyceb55ee2010-11-06 16:05:49 +00002014 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002015 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002016 {
cristyceb55ee2010-11-06 16:05:49 +00002017 Image
2018 clone_image;
2019
2020 CacheInfo
2021 *clone_info;
2022
2023 /*
2024 Clone pixel cache.
2025 */
2026 clone_image=(*image);
2027 clone_image.semaphore=AllocateSemaphoreInfo();
2028 clone_image.reference_count=1;
2029 clone_image.cache=ClonePixelCache(cache_info);
2030 clone_info=(CacheInfo *) clone_image.cache;
2031 status=OpenPixelCache(&clone_image,IOMode,exception);
2032 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002033 {
cristy5a7fbfb2010-11-06 16:10:59 +00002034 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002035 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002036 if (status != MagickFalse)
2037 {
cristy979bf772011-08-08 00:04:15 +00002038 if (cache_info->mode == ReadMode)
2039 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002040 destroy=MagickTrue;
2041 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002042 }
2043 }
cristyceb55ee2010-11-06 16:05:49 +00002044 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002045 }
cristyceb55ee2010-11-06 16:05:49 +00002046 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002047 }
cristy4320e0e2009-09-10 15:00:08 +00002048 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002049 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002050 if (status != MagickFalse)
2051 {
2052 /*
2053 Ensure the image matches the pixel cache morphology.
2054 */
2055 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002056 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002057 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00002058 {
2059 status=OpenPixelCache(image,IOMode,exception);
2060 cache_info=(CacheInfo *) image->cache;
2061 if (cache_info->type == DiskCache)
2062 (void) ClosePixelCacheOnDisk(cache_info);
2063 }
cristy3ed852e2009-09-05 21:47:34 +00002064 }
cristyf84a1932010-01-03 18:00:18 +00002065 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002066 if (status == MagickFalse)
2067 return((Cache) NULL);
2068 return(image->cache);
2069}
2070
2071/*
2072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2073% %
2074% %
2075% %
2076% G e t O n e A u t h e n t i c P i x e l %
2077% %
2078% %
2079% %
2080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2081%
2082% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2083% location. The image background color is returned if an error occurs.
2084%
2085% The format of the GetOneAuthenticPixel() method is:
2086%
cristybb503372010-05-27 20:51:26 +00002087% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002088% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002089%
2090% A description of each parameter follows:
2091%
2092% o image: the image.
2093%
2094% o x,y: These values define the location of the pixel to return.
2095%
2096% o pixel: return a pixel at the specified (x,y) location.
2097%
2098% o exception: return any errors or warnings in this structure.
2099%
2100*/
cristyacbbb7c2010-06-30 18:56:48 +00002101MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002102 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002103{
2104 CacheInfo
2105 *cache_info;
2106
cristy4c08aed2011-07-01 19:47:50 +00002107 register Quantum
2108 *q;
cristy2036f5c2010-09-19 21:18:17 +00002109
cristy2ed42f62011-10-02 19:49:57 +00002110 register ssize_t
2111 i;
2112
cristy3ed852e2009-09-05 21:47:34 +00002113 assert(image != (Image *) NULL);
2114 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002115 assert(image->cache != (Cache) NULL);
2116 cache_info=(CacheInfo *) image->cache;
2117 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002118 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002119 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2120 (GetOneAuthenticPixelFromHandler) NULL)
2121 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2122 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002123 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2124 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002125 {
cristy9e0719b2011-12-29 03:45:45 +00002126 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2127 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2128 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2129 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2130 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002131 return(MagickFalse);
2132 }
2133 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2134 {
2135 PixelChannel
2136 channel;
2137
cristye2a912b2011-12-05 20:02:07 +00002138 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002139 pixel[channel]=q[i];
2140 }
cristy2036f5c2010-09-19 21:18:17 +00002141 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002142}
2143
2144/*
2145%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2146% %
2147% %
2148% %
2149+ 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 %
2150% %
2151% %
2152% %
2153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2154%
2155% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2156% location. The image background color is returned if an error occurs.
2157%
2158% The format of the GetOneAuthenticPixelFromCache() method is:
2159%
2160% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002161% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002162% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002163%
2164% A description of each parameter follows:
2165%
2166% o image: the image.
2167%
2168% o x,y: These values define the location of the pixel to return.
2169%
2170% o pixel: return a pixel at the specified (x,y) location.
2171%
2172% o exception: return any errors or warnings in this structure.
2173%
2174*/
2175static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002176 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002177{
cristy098f78c2010-09-23 17:28:44 +00002178 CacheInfo
2179 *cache_info;
2180
2181 const int
2182 id = GetOpenMPThreadId();
2183
cristy4c08aed2011-07-01 19:47:50 +00002184 register Quantum
2185 *q;
cristy3ed852e2009-09-05 21:47:34 +00002186
cristy2ed42f62011-10-02 19:49:57 +00002187 register ssize_t
2188 i;
2189
cristy0158a4b2010-09-20 13:59:45 +00002190 assert(image != (const Image *) NULL);
2191 assert(image->signature == MagickSignature);
2192 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002193 cache_info=(CacheInfo *) image->cache;
2194 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002195 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002196 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002197 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2198 exception);
2199 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002200 {
cristy9e0719b2011-12-29 03:45:45 +00002201 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2202 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2203 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2204 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2205 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002206 return(MagickFalse);
2207 }
2208 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2209 {
2210 PixelChannel
2211 channel;
2212
cristye2a912b2011-12-05 20:02:07 +00002213 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002214 pixel[channel]=q[i];
2215 }
cristy3ed852e2009-09-05 21:47:34 +00002216 return(MagickTrue);
2217}
2218
2219/*
2220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2221% %
2222% %
2223% %
cristy3ed852e2009-09-05 21:47:34 +00002224% G e t O n e V i r t u a l P i x e l %
2225% %
2226% %
2227% %
2228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2229%
2230% GetOneVirtualPixel() returns a single virtual pixel at the specified
2231% (x,y) location. The image background color is returned if an error occurs.
2232% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2233%
2234% The format of the GetOneVirtualPixel() method is:
2235%
cristybb503372010-05-27 20:51:26 +00002236% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002237% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002238%
2239% A description of each parameter follows:
2240%
2241% o image: the image.
2242%
2243% o x,y: These values define the location of the pixel to return.
2244%
2245% o pixel: return a pixel at the specified (x,y) location.
2246%
2247% o exception: return any errors or warnings in this structure.
2248%
2249*/
2250MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002251 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002252{
cristy3ed852e2009-09-05 21:47:34 +00002253 CacheInfo
2254 *cache_info;
2255
cristy0158a4b2010-09-20 13:59:45 +00002256 const int
2257 id = GetOpenMPThreadId();
2258
cristy4c08aed2011-07-01 19:47:50 +00002259 const Quantum
2260 *p;
cristy2036f5c2010-09-19 21:18:17 +00002261
cristy2ed42f62011-10-02 19:49:57 +00002262 register ssize_t
2263 i;
2264
cristy3ed852e2009-09-05 21:47:34 +00002265 assert(image != (const Image *) NULL);
2266 assert(image->signature == MagickSignature);
2267 assert(image->cache != (Cache) NULL);
2268 cache_info=(CacheInfo *) image->cache;
2269 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002270 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002271 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2272 (GetOneVirtualPixelFromHandler) NULL)
2273 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2274 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002275 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002276 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002277 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002278 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002279 {
cristy9e0719b2011-12-29 03:45:45 +00002280 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2281 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2282 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2283 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2284 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002285 return(MagickFalse);
2286 }
2287 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2288 {
2289 PixelChannel
2290 channel;
2291
cristye2a912b2011-12-05 20:02:07 +00002292 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002293 pixel[channel]=p[i];
2294 }
cristy2036f5c2010-09-19 21:18:17 +00002295 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002296}
2297
2298/*
2299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2300% %
2301% %
2302% %
2303+ 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 %
2304% %
2305% %
2306% %
2307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2308%
2309% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2310% specified (x,y) location. The image background color is returned if an
2311% error occurs.
2312%
2313% The format of the GetOneVirtualPixelFromCache() method is:
2314%
2315% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002316% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002317% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002318%
2319% A description of each parameter follows:
2320%
2321% o image: the image.
2322%
2323% o virtual_pixel_method: the virtual pixel method.
2324%
2325% o x,y: These values define the location of the pixel to return.
2326%
2327% o pixel: return a pixel at the specified (x,y) location.
2328%
2329% o exception: return any errors or warnings in this structure.
2330%
2331*/
2332static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002333 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002334 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002335{
cristy0158a4b2010-09-20 13:59:45 +00002336 CacheInfo
2337 *cache_info;
2338
2339 const int
2340 id = GetOpenMPThreadId();
2341
cristy4c08aed2011-07-01 19:47:50 +00002342 const Quantum
2343 *p;
cristy3ed852e2009-09-05 21:47:34 +00002344
cristy2ed42f62011-10-02 19:49:57 +00002345 register ssize_t
2346 i;
2347
cristye7cc7cf2010-09-21 13:26:47 +00002348 assert(image != (const Image *) NULL);
2349 assert(image->signature == MagickSignature);
2350 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002351 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002352 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002353 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002354 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002355 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002356 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002357 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002358 {
cristy9e0719b2011-12-29 03:45:45 +00002359 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2360 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2361 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2362 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2363 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002364 return(MagickFalse);
2365 }
2366 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2367 {
2368 PixelChannel
2369 channel;
2370
cristye2a912b2011-12-05 20:02:07 +00002371 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002372 pixel[channel]=p[i];
2373 }
cristy3ed852e2009-09-05 21:47:34 +00002374 return(MagickTrue);
2375}
2376
2377/*
2378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2379% %
2380% %
2381% %
cristy3aa93752011-12-18 15:54:24 +00002382% G e t O n e V i r t u a l P i x e l I n f o %
2383% %
2384% %
2385% %
2386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2387%
2388% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2389% location. The image background color is returned if an error occurs. If
2390% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2391%
2392% The format of the GetOneVirtualPixelInfo() method is:
2393%
2394% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2395% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2396% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2397%
2398% A description of each parameter follows:
2399%
2400% o image: the image.
2401%
2402% o virtual_pixel_method: the virtual pixel method.
2403%
2404% o x,y: these values define the location of the pixel to return.
2405%
2406% o pixel: return a pixel at the specified (x,y) location.
2407%
2408% o exception: return any errors or warnings in this structure.
2409%
2410*/
2411MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2412 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2413 PixelInfo *pixel,ExceptionInfo *exception)
2414{
2415 CacheInfo
2416 *cache_info;
2417
2418 const int
2419 id = GetOpenMPThreadId();
2420
2421 register const Quantum
2422 *p;
2423
2424 assert(image != (const Image *) NULL);
2425 assert(image->signature == MagickSignature);
2426 assert(image->cache != (Cache) NULL);
2427 cache_info=(CacheInfo *) image->cache;
2428 assert(cache_info->signature == MagickSignature);
2429 assert(id < (int) cache_info->number_threads);
2430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2431 cache_info->nexus_info[id],exception);
2432 GetPixelInfo(image,pixel);
2433 if (p == (const Quantum *) NULL)
2434 return(MagickFalse);
2435 GetPixelInfoPixel(image,p,pixel);
2436 return(MagickTrue);
2437}
2438
2439/*
2440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2441% %
2442% %
2443% %
cristy3ed852e2009-09-05 21:47:34 +00002444+ G e t P i x e l C a c h e C o l o r s p a c e %
2445% %
2446% %
2447% %
2448%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2449%
2450% GetPixelCacheColorspace() returns the class type of the pixel cache.
2451%
2452% The format of the GetPixelCacheColorspace() method is:
2453%
2454% Colorspace GetPixelCacheColorspace(Cache cache)
2455%
2456% A description of each parameter follows:
2457%
2458% o cache: the pixel cache.
2459%
2460*/
cristya6577ff2011-09-02 19:54:26 +00002461MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002462{
2463 CacheInfo
2464 *cache_info;
2465
2466 assert(cache != (Cache) NULL);
2467 cache_info=(CacheInfo *) cache;
2468 assert(cache_info->signature == MagickSignature);
2469 if (cache_info->debug != MagickFalse)
2470 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2471 cache_info->filename);
2472 return(cache_info->colorspace);
2473}
2474
2475/*
2476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2477% %
2478% %
2479% %
2480+ G e t P i x e l C a c h e M e t h o d s %
2481% %
2482% %
2483% %
2484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2485%
2486% GetPixelCacheMethods() initializes the CacheMethods structure.
2487%
2488% The format of the GetPixelCacheMethods() method is:
2489%
2490% void GetPixelCacheMethods(CacheMethods *cache_methods)
2491%
2492% A description of each parameter follows:
2493%
2494% o cache_methods: Specifies a pointer to a CacheMethods structure.
2495%
2496*/
cristya6577ff2011-09-02 19:54:26 +00002497MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002498{
2499 assert(cache_methods != (CacheMethods *) NULL);
2500 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2501 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2502 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002503 cache_methods->get_virtual_metacontent_from_handler=
2504 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002505 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2506 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002507 cache_methods->get_authentic_metacontent_from_handler=
2508 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002509 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2510 cache_methods->get_one_authentic_pixel_from_handler=
2511 GetOneAuthenticPixelFromCache;
2512 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2513 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2514 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2515}
2516
2517/*
2518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2519% %
2520% %
2521% %
2522+ G e t P i x e l C a c h e N e x u s E x t e n t %
2523% %
2524% %
2525% %
2526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2527%
cristy4c08aed2011-07-01 19:47:50 +00002528% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2529% corresponding with the last call to SetPixelCacheNexusPixels() or
2530% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002531%
2532% The format of the GetPixelCacheNexusExtent() method is:
2533%
2534% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2535% NexusInfo *nexus_info)
2536%
2537% A description of each parameter follows:
2538%
2539% o nexus_info: the nexus info.
2540%
2541*/
cristya6577ff2011-09-02 19:54:26 +00002542MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002543 NexusInfo *nexus_info)
2544{
2545 CacheInfo
2546 *cache_info;
2547
2548 MagickSizeType
2549 extent;
2550
cristy9f027d12011-09-21 01:17:17 +00002551 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002552 cache_info=(CacheInfo *) cache;
2553 assert(cache_info->signature == MagickSignature);
2554 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2555 if (extent == 0)
2556 return((MagickSizeType) cache_info->columns*cache_info->rows);
2557 return(extent);
2558}
2559
2560/*
2561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2562% %
2563% %
2564% %
cristy4c08aed2011-07-01 19:47:50 +00002565+ 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 +00002566% %
2567% %
2568% %
2569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2570%
cristy4c08aed2011-07-01 19:47:50 +00002571% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2572% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002573%
cristy4c08aed2011-07-01 19:47:50 +00002574% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002575%
cristy4c08aed2011-07-01 19:47:50 +00002576% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002577% NexusInfo *nexus_info)
2578%
2579% A description of each parameter follows:
2580%
2581% o cache: the pixel cache.
2582%
cristy4c08aed2011-07-01 19:47:50 +00002583% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002584%
2585*/
cristya6577ff2011-09-02 19:54:26 +00002586MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002587 NexusInfo *nexus_info)
2588{
2589 CacheInfo
2590 *cache_info;
2591
cristy9f027d12011-09-21 01:17:17 +00002592 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002593 cache_info=(CacheInfo *) cache;
2594 assert(cache_info->signature == MagickSignature);
2595 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002596 return((void *) NULL);
2597 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002598}
2599
2600/*
2601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2602% %
2603% %
2604% %
2605+ G e t P i x e l C a c h e N e x u s P i x e l s %
2606% %
2607% %
2608% %
2609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2610%
2611% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2612% cache nexus.
2613%
2614% The format of the GetPixelCacheNexusPixels() method is:
2615%
cristy4c08aed2011-07-01 19:47:50 +00002616% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002617% NexusInfo *nexus_info)
2618%
2619% A description of each parameter follows:
2620%
2621% o cache: the pixel cache.
2622%
2623% o nexus_info: the cache nexus to return the pixels.
2624%
2625*/
cristya6577ff2011-09-02 19:54:26 +00002626MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002627 NexusInfo *nexus_info)
2628{
2629 CacheInfo
2630 *cache_info;
2631
cristy9f027d12011-09-21 01:17:17 +00002632 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002633 cache_info=(CacheInfo *) cache;
2634 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002635 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002636 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002637 return(nexus_info->pixels);
2638}
2639
2640/*
2641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2642% %
2643% %
2644% %
cristy056ba772010-01-02 23:33:54 +00002645+ G e t P i x e l C a c h e P i x e l s %
2646% %
2647% %
2648% %
2649%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2650%
2651% GetPixelCachePixels() returns the pixels associated with the specified image.
2652%
2653% The format of the GetPixelCachePixels() method is:
2654%
cristyf84a1932010-01-03 18:00:18 +00002655% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2656% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002657%
2658% A description of each parameter follows:
2659%
2660% o image: the image.
2661%
2662% o length: the pixel cache length.
2663%
cristyf84a1932010-01-03 18:00:18 +00002664% o exception: return any errors or warnings in this structure.
2665%
cristy056ba772010-01-02 23:33:54 +00002666*/
cristyd1dd6e42011-09-04 01:46:08 +00002667MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002668 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002669{
2670 CacheInfo
2671 *cache_info;
2672
2673 assert(image != (const Image *) NULL);
2674 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002675 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002676 assert(length != (MagickSizeType *) NULL);
2677 assert(exception != (ExceptionInfo *) NULL);
2678 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002679 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002680 assert(cache_info->signature == MagickSignature);
2681 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002682 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002683 return((void *) NULL);
2684 *length=cache_info->length;
2685 return((void *) cache_info->pixels);
2686}
2687
2688/*
2689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2690% %
2691% %
2692% %
cristyb32b90a2009-09-07 21:45:48 +00002693+ 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 +00002694% %
2695% %
2696% %
2697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2698%
2699% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2700%
2701% The format of the GetPixelCacheStorageClass() method is:
2702%
2703% ClassType GetPixelCacheStorageClass(Cache cache)
2704%
2705% A description of each parameter follows:
2706%
2707% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2708%
2709% o cache: the pixel cache.
2710%
2711*/
cristya6577ff2011-09-02 19:54:26 +00002712MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002713{
2714 CacheInfo
2715 *cache_info;
2716
2717 assert(cache != (Cache) NULL);
2718 cache_info=(CacheInfo *) cache;
2719 assert(cache_info->signature == MagickSignature);
2720 if (cache_info->debug != MagickFalse)
2721 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2722 cache_info->filename);
2723 return(cache_info->storage_class);
2724}
2725
2726/*
2727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2728% %
2729% %
2730% %
cristyb32b90a2009-09-07 21:45:48 +00002731+ G e t P i x e l C a c h e T i l e S i z e %
2732% %
2733% %
2734% %
2735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2736%
2737% GetPixelCacheTileSize() returns the pixel cache tile size.
2738%
2739% The format of the GetPixelCacheTileSize() method is:
2740%
cristybb503372010-05-27 20:51:26 +00002741% void GetPixelCacheTileSize(const Image *image,size_t *width,
2742% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002743%
2744% A description of each parameter follows:
2745%
2746% o image: the image.
2747%
2748% o width: the optimize cache tile width in pixels.
2749%
2750% o height: the optimize cache tile height in pixels.
2751%
2752*/
cristya6577ff2011-09-02 19:54:26 +00002753MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002754 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002755{
cristy4c08aed2011-07-01 19:47:50 +00002756 CacheInfo
2757 *cache_info;
2758
cristyb32b90a2009-09-07 21:45:48 +00002759 assert(image != (Image *) NULL);
2760 assert(image->signature == MagickSignature);
2761 if (image->debug != MagickFalse)
2762 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002763 cache_info=(CacheInfo *) image->cache;
2764 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002765 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002766 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002767 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002768 *height=(*width);
2769}
2770
2771/*
2772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2773% %
2774% %
2775% %
2776+ G e t P i x e l C a c h e T y p e %
2777% %
2778% %
2779% %
2780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2781%
2782% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2783%
2784% The format of the GetPixelCacheType() method is:
2785%
2786% CacheType GetPixelCacheType(const Image *image)
2787%
2788% A description of each parameter follows:
2789%
2790% o image: the image.
2791%
2792*/
cristya6577ff2011-09-02 19:54:26 +00002793MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002794{
2795 CacheInfo
2796 *cache_info;
2797
2798 assert(image != (Image *) NULL);
2799 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002800 assert(image->cache != (Cache) NULL);
2801 cache_info=(CacheInfo *) image->cache;
2802 assert(cache_info->signature == MagickSignature);
2803 return(cache_info->type);
2804}
2805
2806/*
2807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2808% %
2809% %
2810% %
cristy3ed852e2009-09-05 21:47:34 +00002811+ 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 %
2812% %
2813% %
2814% %
2815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2816%
2817% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2818% pixel cache. A virtual pixel is any pixel access that is outside the
2819% boundaries of the image cache.
2820%
2821% The format of the GetPixelCacheVirtualMethod() method is:
2822%
2823% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2824%
2825% A description of each parameter follows:
2826%
2827% o image: the image.
2828%
2829*/
cristyd1dd6e42011-09-04 01:46:08 +00002830MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002831{
2832 CacheInfo
2833 *cache_info;
2834
2835 assert(image != (Image *) NULL);
2836 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002837 assert(image->cache != (Cache) NULL);
2838 cache_info=(CacheInfo *) image->cache;
2839 assert(cache_info->signature == MagickSignature);
2840 return(cache_info->virtual_pixel_method);
2841}
2842
2843/*
2844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2845% %
2846% %
2847% %
cristy4c08aed2011-07-01 19:47:50 +00002848+ 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 +00002849% %
2850% %
2851% %
2852%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2853%
cristy4c08aed2011-07-01 19:47:50 +00002854% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2855% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002856%
cristy4c08aed2011-07-01 19:47:50 +00002857% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002858%
cristy4c08aed2011-07-01 19:47:50 +00002859% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002860%
2861% A description of each parameter follows:
2862%
2863% o image: the image.
2864%
2865*/
cristy4c08aed2011-07-01 19:47:50 +00002866static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002867{
2868 CacheInfo
2869 *cache_info;
2870
cristy5c9e6f22010-09-17 17:31:01 +00002871 const int
2872 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002873
cristy4c08aed2011-07-01 19:47:50 +00002874 const void
2875 *metacontent;
2876
cristye7cc7cf2010-09-21 13:26:47 +00002877 assert(image != (const Image *) NULL);
2878 assert(image->signature == MagickSignature);
2879 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002880 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002881 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002882 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002883 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2884 cache_info->nexus_info[id]);
2885 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002886}
2887
2888/*
2889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2890% %
2891% %
2892% %
cristy4c08aed2011-07-01 19:47:50 +00002893+ 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 +00002894% %
2895% %
2896% %
2897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2898%
cristy4c08aed2011-07-01 19:47:50 +00002899% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2900% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002901%
cristy4c08aed2011-07-01 19:47:50 +00002902% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002903%
cristy4c08aed2011-07-01 19:47:50 +00002904% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002905% NexusInfo *nexus_info)
2906%
2907% A description of each parameter follows:
2908%
2909% o cache: the pixel cache.
2910%
cristy4c08aed2011-07-01 19:47:50 +00002911% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002912%
2913*/
cristya6577ff2011-09-02 19:54:26 +00002914MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002915 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002916{
2917 CacheInfo
2918 *cache_info;
2919
cristye7cc7cf2010-09-21 13:26:47 +00002920 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002921 cache_info=(CacheInfo *) cache;
2922 assert(cache_info->signature == MagickSignature);
2923 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002924 return((void *) NULL);
2925 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002926}
2927
2928/*
2929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2930% %
2931% %
2932% %
cristy4c08aed2011-07-01 19:47:50 +00002933% 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 +00002934% %
2935% %
2936% %
2937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2938%
cristy4c08aed2011-07-01 19:47:50 +00002939% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2940% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2941% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002942%
cristy4c08aed2011-07-01 19:47:50 +00002943% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002944%
cristy4c08aed2011-07-01 19:47:50 +00002945% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002946%
2947% A description of each parameter follows:
2948%
2949% o image: the image.
2950%
2951*/
cristy4c08aed2011-07-01 19:47:50 +00002952MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002953{
2954 CacheInfo
2955 *cache_info;
2956
cristy2036f5c2010-09-19 21:18:17 +00002957 const int
2958 id = GetOpenMPThreadId();
2959
cristy4c08aed2011-07-01 19:47:50 +00002960 const void
2961 *metacontent;
2962
cristy3ed852e2009-09-05 21:47:34 +00002963 assert(image != (const Image *) NULL);
2964 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002965 assert(image->cache != (Cache) NULL);
2966 cache_info=(CacheInfo *) image->cache;
2967 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002968 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2969 (GetVirtualMetacontentFromHandler) NULL)
2970 {
2971 metacontent=cache_info->methods.
2972 get_virtual_metacontent_from_handler(image);
2973 return(metacontent);
2974 }
cristy2036f5c2010-09-19 21:18:17 +00002975 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002976 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2977 cache_info->nexus_info[id]);
2978 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002979}
2980
2981/*
2982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2983% %
2984% %
2985% %
2986+ 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 %
2987% %
2988% %
2989% %
2990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2991%
2992% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2993% pixel cache as defined by the geometry parameters. A pointer to the pixels
2994% is returned if the pixels are transferred, otherwise a NULL is returned.
2995%
2996% The format of the GetVirtualPixelsFromNexus() method is:
2997%
cristy4c08aed2011-07-01 19:47:50 +00002998% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002999% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003000% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3001% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003002%
3003% A description of each parameter follows:
3004%
3005% o image: the image.
3006%
3007% o virtual_pixel_method: the virtual pixel method.
3008%
3009% o x,y,columns,rows: These values define the perimeter of a region of
3010% pixels.
3011%
3012% o nexus_info: the cache nexus to acquire.
3013%
3014% o exception: return any errors or warnings in this structure.
3015%
3016*/
3017
cristybb503372010-05-27 20:51:26 +00003018static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003019 DitherMatrix[64] =
3020 {
3021 0, 48, 12, 60, 3, 51, 15, 63,
3022 32, 16, 44, 28, 35, 19, 47, 31,
3023 8, 56, 4, 52, 11, 59, 7, 55,
3024 40, 24, 36, 20, 43, 27, 39, 23,
3025 2, 50, 14, 62, 1, 49, 13, 61,
3026 34, 18, 46, 30, 33, 17, 45, 29,
3027 10, 58, 6, 54, 9, 57, 5, 53,
3028 42, 26, 38, 22, 41, 25, 37, 21
3029 };
3030
cristybb503372010-05-27 20:51:26 +00003031static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003032{
cristybb503372010-05-27 20:51:26 +00003033 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003034 index;
3035
3036 index=x+DitherMatrix[x & 0x07]-32L;
3037 if (index < 0L)
3038 return(0L);
cristybb503372010-05-27 20:51:26 +00003039 if (index >= (ssize_t) columns)
3040 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003041 return(index);
3042}
3043
cristybb503372010-05-27 20:51:26 +00003044static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003045{
cristybb503372010-05-27 20:51:26 +00003046 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003047 index;
3048
3049 index=y+DitherMatrix[y & 0x07]-32L;
3050 if (index < 0L)
3051 return(0L);
cristybb503372010-05-27 20:51:26 +00003052 if (index >= (ssize_t) rows)
3053 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003054 return(index);
3055}
3056
cristybb503372010-05-27 20:51:26 +00003057static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003058{
3059 if (x < 0L)
3060 return(0L);
cristybb503372010-05-27 20:51:26 +00003061 if (x >= (ssize_t) columns)
3062 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003063 return(x);
3064}
3065
cristybb503372010-05-27 20:51:26 +00003066static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003067{
3068 if (y < 0L)
3069 return(0L);
cristybb503372010-05-27 20:51:26 +00003070 if (y >= (ssize_t) rows)
3071 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003072 return(y);
3073}
3074
cristybb503372010-05-27 20:51:26 +00003075static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003076{
cristybb503372010-05-27 20:51:26 +00003077 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003078}
3079
cristybb503372010-05-27 20:51:26 +00003080static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003081{
cristybb503372010-05-27 20:51:26 +00003082 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003083}
3084
cristybb503372010-05-27 20:51:26 +00003085static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3086 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003087{
3088 MagickModulo
3089 modulo;
3090
cristy6162bb42011-07-18 11:34:09 +00003091 /*
3092 Compute the remainder of dividing offset by extent. It returns not only
3093 the quotient (tile the offset falls in) but also the positive remainer
3094 within that tile such that 0 <= remainder < extent. This method is
3095 essentially a ldiv() using a floored modulo division rather than the
3096 normal default truncated modulo division.
3097 */
cristybb503372010-05-27 20:51:26 +00003098 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003099 if (offset < 0L)
3100 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003101 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003102 return(modulo);
3103}
3104
cristya6577ff2011-09-02 19:54:26 +00003105MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003106 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3107 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003108 ExceptionInfo *exception)
3109{
3110 CacheInfo
3111 *cache_info;
3112
3113 MagickOffsetType
3114 offset;
3115
3116 MagickSizeType
3117 length,
3118 number_pixels;
3119
3120 NexusInfo
3121 **virtual_nexus;
3122
cristy4c08aed2011-07-01 19:47:50 +00003123 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003124 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003125 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003126
3127 RectangleInfo
3128 region;
3129
cristy4c08aed2011-07-01 19:47:50 +00003130 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003131 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003132
cristy4c08aed2011-07-01 19:47:50 +00003133 register const void
3134 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003135
cristy4c08aed2011-07-01 19:47:50 +00003136 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003137 *restrict q;
3138
cristybb503372010-05-27 20:51:26 +00003139 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003140 i,
3141 u;
cristy3ed852e2009-09-05 21:47:34 +00003142
cristy4c08aed2011-07-01 19:47:50 +00003143 register unsigned char
3144 *restrict s;
3145
cristy105ba3c2011-07-18 02:28:38 +00003146 ssize_t
3147 v;
3148
cristy4c08aed2011-07-01 19:47:50 +00003149 void
cristy105ba3c2011-07-18 02:28:38 +00003150 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003151
cristy3ed852e2009-09-05 21:47:34 +00003152 /*
3153 Acquire pixels.
3154 */
cristye7cc7cf2010-09-21 13:26:47 +00003155 assert(image != (const Image *) NULL);
3156 assert(image->signature == MagickSignature);
3157 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003158 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003159 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003160 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003161 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003162 region.x=x;
3163 region.y=y;
3164 region.width=columns;
3165 region.height=rows;
3166 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003167 if (pixels == (Quantum *) NULL)
3168 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003169 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003170 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3171 nexus_info->region.x;
3172 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3173 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003174 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3175 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003176 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3177 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003178 {
3179 MagickBooleanType
3180 status;
3181
3182 /*
3183 Pixel request is inside cache extents.
3184 */
cristy4c08aed2011-07-01 19:47:50 +00003185 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003186 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003187 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3188 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003189 return((const Quantum *) NULL);
3190 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003191 {
cristy4c08aed2011-07-01 19:47:50 +00003192 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003193 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003194 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003195 }
cristyacd2ed22011-08-30 01:44:23 +00003196 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003197 }
3198 /*
3199 Pixel request is outside cache extents.
3200 */
cristy4c08aed2011-07-01 19:47:50 +00003201 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003202 virtual_nexus=AcquirePixelCacheNexus(1);
3203 if (virtual_nexus == (NexusInfo **) NULL)
3204 {
cristy4c08aed2011-07-01 19:47:50 +00003205 if (virtual_nexus != (NexusInfo **) NULL)
3206 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003207 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3208 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003209 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003210 }
cristy105ba3c2011-07-18 02:28:38 +00003211 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3212 sizeof(*virtual_pixel));
3213 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003214 switch (virtual_pixel_method)
3215 {
cristy4c08aed2011-07-01 19:47:50 +00003216 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003217 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003218 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003219 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003220 case MaskVirtualPixelMethod:
3221 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003222 case EdgeVirtualPixelMethod:
3223 case CheckerTileVirtualPixelMethod:
3224 case HorizontalTileVirtualPixelMethod:
3225 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003226 {
cristy4c08aed2011-07-01 19:47:50 +00003227 if (cache_info->metacontent_extent != 0)
3228 {
cristy6162bb42011-07-18 11:34:09 +00003229 /*
3230 Acquire a metacontent buffer.
3231 */
cristya64b85d2011-09-14 01:02:31 +00003232 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003233 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003234 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003235 {
cristy4c08aed2011-07-01 19:47:50 +00003236 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3237 (void) ThrowMagickException(exception,GetMagickModule(),
3238 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3239 return((const Quantum *) NULL);
3240 }
cristy105ba3c2011-07-18 02:28:38 +00003241 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003242 cache_info->metacontent_extent);
3243 }
3244 switch (virtual_pixel_method)
3245 {
3246 case BlackVirtualPixelMethod:
3247 {
cristy30301712011-07-18 15:06:51 +00003248 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3249 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003250 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3251 break;
3252 }
3253 case GrayVirtualPixelMethod:
3254 {
cristy30301712011-07-18 15:06:51 +00003255 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003256 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3257 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003258 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3259 break;
3260 }
3261 case TransparentVirtualPixelMethod:
3262 {
cristy30301712011-07-18 15:06:51 +00003263 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3264 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003265 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3266 break;
3267 }
3268 case MaskVirtualPixelMethod:
3269 case WhiteVirtualPixelMethod:
3270 {
cristy30301712011-07-18 15:06:51 +00003271 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3272 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003273 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3274 break;
3275 }
3276 default:
3277 {
cristy9e0719b2011-12-29 03:45:45 +00003278 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3279 virtual_pixel);
3280 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3281 virtual_pixel);
3282 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3283 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003284 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003285 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3286 virtual_pixel);
3287 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3288 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003289 break;
3290 }
3291 }
cristy3ed852e2009-09-05 21:47:34 +00003292 break;
3293 }
3294 default:
cristy3ed852e2009-09-05 21:47:34 +00003295 break;
cristy3ed852e2009-09-05 21:47:34 +00003296 }
cristybb503372010-05-27 20:51:26 +00003297 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003298 {
cristybb503372010-05-27 20:51:26 +00003299 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003300 {
3301 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003302 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003303 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3304 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003305 {
3306 MagickModulo
3307 x_modulo,
3308 y_modulo;
3309
3310 /*
3311 Transfer a single pixel.
3312 */
3313 length=(MagickSizeType) 1;
3314 switch (virtual_pixel_method)
3315 {
cristy3ed852e2009-09-05 21:47:34 +00003316 default:
3317 {
3318 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003319 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003320 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003321 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003322 break;
3323 }
3324 case RandomVirtualPixelMethod:
3325 {
3326 if (cache_info->random_info == (RandomInfo *) NULL)
3327 cache_info->random_info=AcquireRandomInfo();
3328 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003329 RandomX(cache_info->random_info,cache_info->columns),
3330 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003331 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003332 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003333 break;
3334 }
3335 case DitherVirtualPixelMethod:
3336 {
3337 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003338 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003339 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003340 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003341 break;
3342 }
3343 case TileVirtualPixelMethod:
3344 {
3345 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3346 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3347 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003348 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003349 exception);
cristy4c08aed2011-07-01 19:47:50 +00003350 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003351 break;
3352 }
3353 case MirrorVirtualPixelMethod:
3354 {
3355 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3356 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003357 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003358 x_modulo.remainder-1L;
3359 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3360 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003361 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003362 y_modulo.remainder-1L;
3363 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003364 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003365 exception);
cristy4c08aed2011-07-01 19:47:50 +00003366 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003367 break;
3368 }
3369 case HorizontalTileEdgeVirtualPixelMethod:
3370 {
3371 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3372 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003373 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003374 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003375 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003376 break;
3377 }
3378 case VerticalTileEdgeVirtualPixelMethod:
3379 {
3380 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3381 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003382 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003383 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003384 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3385 break;
3386 }
3387 case BackgroundVirtualPixelMethod:
3388 case BlackVirtualPixelMethod:
3389 case GrayVirtualPixelMethod:
3390 case TransparentVirtualPixelMethod:
3391 case MaskVirtualPixelMethod:
3392 case WhiteVirtualPixelMethod:
3393 {
3394 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003395 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003396 break;
3397 }
3398 case EdgeVirtualPixelMethod:
3399 case CheckerTileVirtualPixelMethod:
3400 {
3401 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3402 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3403 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3404 {
3405 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003406 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003407 break;
3408 }
3409 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3410 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3411 exception);
3412 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3413 break;
3414 }
3415 case HorizontalTileVirtualPixelMethod:
3416 {
3417 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3418 {
3419 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003420 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003421 break;
3422 }
3423 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3424 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3425 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3426 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3427 exception);
3428 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3429 break;
3430 }
3431 case VerticalTileVirtualPixelMethod:
3432 {
3433 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3434 {
3435 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003436 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003437 break;
3438 }
3439 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3440 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3441 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3442 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3443 exception);
3444 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003445 break;
3446 }
3447 }
cristy4c08aed2011-07-01 19:47:50 +00003448 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003449 break;
cristyed231572011-07-14 02:18:59 +00003450 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003451 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003452 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003453 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003454 {
3455 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3456 s+=cache_info->metacontent_extent;
3457 }
cristy3ed852e2009-09-05 21:47:34 +00003458 continue;
3459 }
3460 /*
3461 Transfer a run of pixels.
3462 */
cristy4c08aed2011-07-01 19:47:50 +00003463 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3464 length,1UL,*virtual_nexus,exception);
3465 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003466 break;
cristy4c08aed2011-07-01 19:47:50 +00003467 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003468 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3469 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003470 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003471 {
cristy4c08aed2011-07-01 19:47:50 +00003472 (void) memcpy(s,r,(size_t) length);
3473 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003474 }
3475 }
3476 }
cristy4c08aed2011-07-01 19:47:50 +00003477 /*
3478 Free resources.
3479 */
cristy105ba3c2011-07-18 02:28:38 +00003480 if (virtual_metacontent != (void *) NULL)
3481 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003482 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3483 return(pixels);
3484}
3485
3486/*
3487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3488% %
3489% %
3490% %
3491+ G e t V i r t u a l P i x e l C a c h e %
3492% %
3493% %
3494% %
3495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3496%
3497% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3498% cache as defined by the geometry parameters. A pointer to the pixels
3499% is returned if the pixels are transferred, otherwise a NULL is returned.
3500%
3501% The format of the GetVirtualPixelCache() method is:
3502%
cristy4c08aed2011-07-01 19:47:50 +00003503% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003504% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3505% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003506% ExceptionInfo *exception)
3507%
3508% A description of each parameter follows:
3509%
3510% o image: the image.
3511%
3512% o virtual_pixel_method: the virtual pixel method.
3513%
3514% o x,y,columns,rows: These values define the perimeter of a region of
3515% pixels.
3516%
3517% o exception: return any errors or warnings in this structure.
3518%
3519*/
cristy4c08aed2011-07-01 19:47:50 +00003520static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003521 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3522 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003523{
3524 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003525 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003526
cristy5c9e6f22010-09-17 17:31:01 +00003527 const int
3528 id = GetOpenMPThreadId();
3529
cristy4c08aed2011-07-01 19:47:50 +00003530 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003531 *p;
cristy4c08aed2011-07-01 19:47:50 +00003532
cristye7cc7cf2010-09-21 13:26:47 +00003533 assert(image != (const Image *) NULL);
3534 assert(image->signature == MagickSignature);
3535 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003536 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003537 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003538 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003539 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003540 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003541 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003542}
3543
3544/*
3545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3546% %
3547% %
3548% %
3549% G e t V i r t u a l P i x e l Q u e u e %
3550% %
3551% %
3552% %
3553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3554%
cristy4c08aed2011-07-01 19:47:50 +00003555% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3556% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003557%
3558% The format of the GetVirtualPixelQueue() method is:
3559%
cristy4c08aed2011-07-01 19:47:50 +00003560% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003561%
3562% A description of each parameter follows:
3563%
3564% o image: the image.
3565%
3566*/
cristy4c08aed2011-07-01 19:47:50 +00003567MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003568{
3569 CacheInfo
3570 *cache_info;
3571
cristy2036f5c2010-09-19 21:18:17 +00003572 const int
3573 id = GetOpenMPThreadId();
3574
cristy3ed852e2009-09-05 21:47:34 +00003575 assert(image != (const Image *) NULL);
3576 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003577 assert(image->cache != (Cache) NULL);
3578 cache_info=(CacheInfo *) image->cache;
3579 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003580 if (cache_info->methods.get_virtual_pixels_handler !=
3581 (GetVirtualPixelsHandler) NULL)
3582 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003583 assert(id < (int) cache_info->number_threads);
3584 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003585}
3586
3587/*
3588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3589% %
3590% %
3591% %
3592% G e t V i r t u a l P i x e l s %
3593% %
3594% %
3595% %
3596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3597%
3598% GetVirtualPixels() returns an immutable pixel region. If the
3599% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003600% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003601% copy of the pixels or it may point to the original pixels in memory.
3602% Performance is maximized if the selected region is part of one row, or one
3603% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003604% (without a copy) if the image is in memory, or in a memory-mapped file. The
3605% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003606%
3607% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003608% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3609% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3610% access the meta-content (of type void) corresponding to the the
3611% region.
cristy3ed852e2009-09-05 21:47:34 +00003612%
3613% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3614%
3615% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3616% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3617% GetCacheViewAuthenticPixels() instead.
3618%
3619% The format of the GetVirtualPixels() method is:
3620%
cristy4c08aed2011-07-01 19:47:50 +00003621% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003622% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003623% ExceptionInfo *exception)
3624%
3625% A description of each parameter follows:
3626%
3627% o image: the image.
3628%
3629% o x,y,columns,rows: These values define the perimeter of a region of
3630% pixels.
3631%
3632% o exception: return any errors or warnings in this structure.
3633%
3634*/
cristy4c08aed2011-07-01 19:47:50 +00003635MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003636 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3637 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003638{
3639 CacheInfo
3640 *cache_info;
3641
cristy2036f5c2010-09-19 21:18:17 +00003642 const int
3643 id = GetOpenMPThreadId();
3644
cristy4c08aed2011-07-01 19:47:50 +00003645 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003646 *p;
cristy4c08aed2011-07-01 19:47:50 +00003647
cristy3ed852e2009-09-05 21:47:34 +00003648 assert(image != (const Image *) NULL);
3649 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003650 assert(image->cache != (Cache) NULL);
3651 cache_info=(CacheInfo *) image->cache;
3652 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003653 if (cache_info->methods.get_virtual_pixel_handler !=
3654 (GetVirtualPixelHandler) NULL)
3655 return(cache_info->methods.get_virtual_pixel_handler(image,
3656 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003657 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003658 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003659 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003660 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003661}
3662
3663/*
3664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3665% %
3666% %
3667% %
3668+ 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 %
3669% %
3670% %
3671% %
3672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3673%
cristy4c08aed2011-07-01 19:47:50 +00003674% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3675% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003676%
3677% The format of the GetVirtualPixelsCache() method is:
3678%
cristy4c08aed2011-07-01 19:47:50 +00003679% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003680%
3681% A description of each parameter follows:
3682%
3683% o image: the image.
3684%
3685*/
cristy4c08aed2011-07-01 19:47:50 +00003686static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003687{
3688 CacheInfo
3689 *cache_info;
3690
cristy5c9e6f22010-09-17 17:31:01 +00003691 const int
3692 id = GetOpenMPThreadId();
3693
cristye7cc7cf2010-09-21 13:26:47 +00003694 assert(image != (const Image *) NULL);
3695 assert(image->signature == MagickSignature);
3696 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003697 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003698 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003699 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003700 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003701}
3702
3703/*
3704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3705% %
3706% %
3707% %
3708+ G e t V i r t u a l P i x e l s N e x u s %
3709% %
3710% %
3711% %
3712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3713%
3714% GetVirtualPixelsNexus() returns the pixels associated with the specified
3715% cache nexus.
3716%
3717% The format of the GetVirtualPixelsNexus() method is:
3718%
cristy4c08aed2011-07-01 19:47:50 +00003719% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003720% NexusInfo *nexus_info)
3721%
3722% A description of each parameter follows:
3723%
3724% o cache: the pixel cache.
3725%
3726% o nexus_info: the cache nexus to return the colormap pixels.
3727%
3728*/
cristya6577ff2011-09-02 19:54:26 +00003729MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003730 NexusInfo *nexus_info)
3731{
3732 CacheInfo
3733 *cache_info;
3734
cristye7cc7cf2010-09-21 13:26:47 +00003735 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003736 cache_info=(CacheInfo *) cache;
3737 assert(cache_info->signature == MagickSignature);
3738 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003739 return((Quantum *) NULL);
3740 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003741}
3742
3743/*
3744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3745% %
3746% %
3747% %
3748+ M a s k P i x e l C a c h e N e x u s %
3749% %
3750% %
3751% %
3752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3753%
3754% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3755% The method returns MagickTrue if the pixel region is masked, otherwise
3756% MagickFalse.
3757%
3758% The format of the MaskPixelCacheNexus() method is:
3759%
3760% MagickBooleanType MaskPixelCacheNexus(Image *image,
3761% NexusInfo *nexus_info,ExceptionInfo *exception)
3762%
3763% A description of each parameter follows:
3764%
3765% o image: the image.
3766%
3767% o nexus_info: the cache nexus to clip.
3768%
3769% o exception: return any errors or warnings in this structure.
3770%
3771*/
cristy3ed852e2009-09-05 21:47:34 +00003772static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3773 ExceptionInfo *exception)
3774{
3775 CacheInfo
3776 *cache_info;
3777
cristy3ed852e2009-09-05 21:47:34 +00003778 MagickSizeType
3779 number_pixels;
3780
3781 NexusInfo
3782 **clip_nexus,
3783 **image_nexus;
3784
cristy4c08aed2011-07-01 19:47:50 +00003785 register const Quantum
3786 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003787 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003788
cristy4c08aed2011-07-01 19:47:50 +00003789 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003790 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003791
cristye076a6e2010-08-15 19:59:43 +00003792 register ssize_t
cristyc57486d2012-01-02 17:46:50 +00003793 x;
cristye076a6e2010-08-15 19:59:43 +00003794
cristy3ed852e2009-09-05 21:47:34 +00003795 /*
cristyc57486d2012-01-02 17:46:50 +00003796 Prevent updates to image pixels specified by the mask.
cristy3ed852e2009-09-05 21:47:34 +00003797 */
3798 if (image->debug != MagickFalse)
3799 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3800 if (image->mask == (Image *) NULL)
3801 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003802 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003803 if (cache_info == (Cache) NULL)
3804 return(MagickFalse);
3805 image_nexus=AcquirePixelCacheNexus(1);
3806 clip_nexus=AcquirePixelCacheNexus(1);
3807 if ((image_nexus == (NexusInfo **) NULL) ||
3808 (clip_nexus == (NexusInfo **) NULL))
3809 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003810 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3811 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3812 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003813 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003814 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3815 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003816 nexus_info->region.height,clip_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003817 number_pixels=(MagickSizeType) nexus_info->region.width*
3818 nexus_info->region.height;
cristyc57486d2012-01-02 17:46:50 +00003819 for (x=0; x < (ssize_t) number_pixels; x++)
cristy3ed852e2009-09-05 21:47:34 +00003820 {
cristyc57486d2012-01-02 17:46:50 +00003821 MagickRealType
3822 alpha,
3823 Da,
3824 gamma,
3825 Sa;
3826
3827 register ssize_t
3828 i;
3829
cristy4c08aed2011-07-01 19:47:50 +00003830 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003831 break;
cristyc57486d2012-01-02 17:46:50 +00003832 Sa=QuantumScale*GetPixelIntensity(image->mask,r);
3833 Da=QuantumScale*GetPixelAlpha(image,q);
3834 alpha=Sa*(-Da)+Sa+Da;
3835 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
3836 for (i=0; i < (ssize_t) image->number_channels; i++)
3837 {
3838 MagickRealType
3839 Dc,
3840 pixel,
3841 Sc;
3842
3843 PixelChannel
3844 channel;
3845
3846 PixelTrait
3847 traits;
3848
3849 channel=GetPixelChannelMapChannel(image,i);
3850 traits=GetPixelChannelMapTraits(image,channel);
3851 if (traits == UndefinedPixelTrait)
3852 continue;
3853 Sc=(MagickRealType) p[i];
3854 Dc=(MagickRealType) q[i];
cristya3bcb792012-01-10 19:39:28 +00003855 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
cristyc57486d2012-01-02 17:46:50 +00003856 q[i]=ClampToQuantum(pixel);
3857 }
3858 p+=GetPixelChannels(image);
3859 q+=GetPixelChannels(image);
cristy2e814ac2012-01-06 01:59:36 +00003860 r+=GetPixelChannels(image->mask);
cristy3ed852e2009-09-05 21:47:34 +00003861 }
3862 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3863 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristyc57486d2012-01-02 17:46:50 +00003864 if (x < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003865 return(MagickFalse);
3866 return(MagickTrue);
3867}
3868
3869/*
3870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3871% %
3872% %
3873% %
3874+ O p e n P i x e l C a c h e %
3875% %
3876% %
3877% %
3878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3879%
3880% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3881% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003882% metacontent, and memory mapping the cache if it is disk based. The cache
3883% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003884%
3885% The format of the OpenPixelCache() method is:
3886%
3887% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3888% ExceptionInfo *exception)
3889%
3890% A description of each parameter follows:
3891%
3892% o image: the image.
3893%
3894% o mode: ReadMode, WriteMode, or IOMode.
3895%
3896% o exception: return any errors or warnings in this structure.
3897%
3898*/
3899
cristyd43a46b2010-01-21 02:13:41 +00003900static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003901{
3902 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003903 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003904 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003905 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003906 {
3907 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003908 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003909 cache_info->length);
3910 }
3911}
3912
3913static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3914{
3915 CacheInfo
3916 *cache_info;
3917
3918 MagickOffsetType
3919 count,
3920 extent,
3921 offset;
3922
3923 cache_info=(CacheInfo *) image->cache;
3924 if (image->debug != MagickFalse)
3925 {
3926 char
3927 format[MaxTextExtent],
3928 message[MaxTextExtent];
3929
cristyb9080c92009-12-01 20:13:26 +00003930 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003931 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003932 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003933 cache_info->cache_filename,cache_info->file,format);
3934 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3935 }
3936 if (length != (MagickSizeType) ((MagickOffsetType) length))
3937 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003938 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003939 if (extent < 0)
3940 return(MagickFalse);
3941 if ((MagickSizeType) extent >= length)
3942 return(MagickTrue);
3943 offset=(MagickOffsetType) length-1;
3944 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3945 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3946}
3947
3948static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3949 ExceptionInfo *exception)
3950{
cristy3ed852e2009-09-05 21:47:34 +00003951 CacheInfo
3952 *cache_info,
3953 source_info;
3954
cristyf3a6a9d2010-11-07 21:02:56 +00003955 char
3956 format[MaxTextExtent],
3957 message[MaxTextExtent];
3958
cristy4c08aed2011-07-01 19:47:50 +00003959 MagickBooleanType
3960 status;
3961
cristy3ed852e2009-09-05 21:47:34 +00003962 MagickSizeType
3963 length,
3964 number_pixels;
3965
cristy3b8fe922011-12-29 18:56:23 +00003966 PixelChannelMap
3967 *p,
3968 *q;
3969
cristy3ed852e2009-09-05 21:47:34 +00003970 size_t
cristye076a6e2010-08-15 19:59:43 +00003971 columns,
cristy3ed852e2009-09-05 21:47:34 +00003972 packet_size;
3973
cristye7cc7cf2010-09-21 13:26:47 +00003974 assert(image != (const Image *) NULL);
3975 assert(image->signature == MagickSignature);
3976 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003977 if (image->debug != MagickFalse)
3978 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3979 if ((image->columns == 0) || (image->rows == 0))
3980 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3981 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003982 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003983 source_info=(*cache_info);
3984 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003985 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003986 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003987 cache_info->storage_class=image->storage_class;
3988 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003989 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00003990 cache_info->rows=image->rows;
3991 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003992 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003993 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003994 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3995 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003996 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003997 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003998 if (image->ping != MagickFalse)
3999 {
cristy73724512010-04-12 14:43:14 +00004000 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004001 cache_info->pixels=(Quantum *) NULL;
4002 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004003 cache_info->length=0;
4004 return(MagickTrue);
4005 }
cristy3ed852e2009-09-05 21:47:34 +00004006 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004007 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004008 if (image->metacontent_extent != 0)
4009 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004010 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004011 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004012 if (cache_info->columns != columns)
4013 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4014 image->filename);
4015 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00004016 p=cache_info->channel_map;
4017 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00004018 if ((cache_info->type != UndefinedCache) &&
4019 (cache_info->columns <= source_info.columns) &&
4020 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004021 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00004022 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004023 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4024 {
4025 /*
4026 Inline pixel cache clone optimization.
4027 */
4028 if ((cache_info->columns == source_info.columns) &&
4029 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004030 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00004031 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004032 (cache_info->metacontent_extent == source_info.metacontent_extent))
4033 return(MagickTrue);
4034 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4035 }
cristy3ed852e2009-09-05 21:47:34 +00004036 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004037 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004038 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004039 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4040 {
4041 status=AcquireMagickResource(MemoryResource,cache_info->length);
4042 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4043 (cache_info->type == MemoryCache))
4044 {
cristyd43a46b2010-01-21 02:13:41 +00004045 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004046 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004047 cache_info->pixels=source_info.pixels;
4048 else
4049 {
4050 /*
4051 Create memory pixel cache.
4052 */
cristy4c08aed2011-07-01 19:47:50 +00004053 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004054 if (image->debug != MagickFalse)
4055 {
cristy32cacff2011-12-31 03:36:27 +00004056 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004057 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004058 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4059 cache_info->filename,cache_info->mapped != MagickFalse ?
4060 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004061 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004062 format);
cristy3ed852e2009-09-05 21:47:34 +00004063 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4064 message);
4065 }
cristy3ed852e2009-09-05 21:47:34 +00004066 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004067 cache_info->metacontent=(void *) NULL;
4068 if (cache_info->metacontent_extent != 0)
4069 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004070 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00004071 if ((source_info.storage_class != UndefinedClass) &&
4072 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004073 {
cristy4c08aed2011-07-01 19:47:50 +00004074 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004075 exception);
4076 RelinquishPixelCachePixels(&source_info);
4077 }
cristy4c08aed2011-07-01 19:47:50 +00004078 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004079 }
4080 }
4081 RelinquishMagickResource(MemoryResource,cache_info->length);
4082 }
4083 /*
4084 Create pixel cache on disk.
4085 */
4086 status=AcquireMagickResource(DiskResource,cache_info->length);
4087 if (status == MagickFalse)
4088 {
4089 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4090 "CacheResourcesExhausted","`%s'",image->filename);
4091 return(MagickFalse);
4092 }
cristy413f1302012-01-01 17:48:27 +00004093 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4094 {
4095 (void) ClosePixelCacheOnDisk(cache_info);
4096 *cache_info->cache_filename='\0';
4097 }
cristy3ed852e2009-09-05 21:47:34 +00004098 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4099 {
4100 RelinquishMagickResource(DiskResource,cache_info->length);
4101 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4102 image->filename);
4103 return(MagickFalse);
4104 }
4105 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4106 cache_info->length);
4107 if (status == MagickFalse)
4108 {
4109 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4110 image->filename);
4111 return(MagickFalse);
4112 }
cristyed231572011-07-14 02:18:59 +00004113 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004114 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004115 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004116 cache_info->type=DiskCache;
4117 else
4118 {
4119 status=AcquireMagickResource(MapResource,cache_info->length);
4120 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4121 (cache_info->type != MemoryCache))
4122 cache_info->type=DiskCache;
4123 else
4124 {
cristy4c08aed2011-07-01 19:47:50 +00004125 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004126 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004127 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004128 {
cristy3ed852e2009-09-05 21:47:34 +00004129 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004130 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004131 }
4132 else
4133 {
4134 /*
4135 Create file-backed memory-mapped pixel cache.
4136 */
cristy4c08aed2011-07-01 19:47:50 +00004137 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004138 (void) ClosePixelCacheOnDisk(cache_info);
4139 cache_info->type=MapCache;
4140 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004141 cache_info->metacontent=(void *) NULL;
4142 if (cache_info->metacontent_extent != 0)
4143 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004144 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00004145 if ((source_info.storage_class != UndefinedClass) &&
4146 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004147 {
4148 status=ClonePixelCachePixels(cache_info,&source_info,
4149 exception);
4150 RelinquishPixelCachePixels(&source_info);
4151 }
4152 if (image->debug != MagickFalse)
4153 {
cristy413f1302012-01-01 17:48:27 +00004154 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004155 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004156 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004157 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004158 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004159 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004160 format);
cristy3ed852e2009-09-05 21:47:34 +00004161 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4162 message);
4163 }
cristy4c08aed2011-07-01 19:47:50 +00004164 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004165 }
4166 }
4167 RelinquishMagickResource(MapResource,cache_info->length);
4168 }
cristy4c08aed2011-07-01 19:47:50 +00004169 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00004170 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004171 {
4172 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4173 RelinquishPixelCachePixels(&source_info);
4174 }
4175 if (image->debug != MagickFalse)
4176 {
cristyb9080c92009-12-01 20:13:26 +00004177 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004178 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004179 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004180 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004181 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004182 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004183 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4184 }
cristy4c08aed2011-07-01 19:47:50 +00004185 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004186}
4187
4188/*
4189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4190% %
4191% %
4192% %
4193+ P e r s i s t P i x e l C a c h e %
4194% %
4195% %
4196% %
4197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4198%
4199% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4200% persistent pixel cache is one that resides on disk and is not destroyed
4201% when the program exits.
4202%
4203% The format of the PersistPixelCache() method is:
4204%
4205% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4206% const MagickBooleanType attach,MagickOffsetType *offset,
4207% ExceptionInfo *exception)
4208%
4209% A description of each parameter follows:
4210%
4211% o image: the image.
4212%
4213% o filename: the persistent pixel cache filename.
4214%
cristyf3a6a9d2010-11-07 21:02:56 +00004215% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004216%
cristy3ed852e2009-09-05 21:47:34 +00004217% o initialize: A value other than zero initializes the persistent pixel
4218% cache.
4219%
4220% o offset: the offset in the persistent cache to store pixels.
4221%
4222% o exception: return any errors or warnings in this structure.
4223%
4224*/
4225MagickExport MagickBooleanType PersistPixelCache(Image *image,
4226 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4227 ExceptionInfo *exception)
4228{
4229 CacheInfo
4230 *cache_info,
4231 *clone_info;
4232
4233 Image
4234 clone_image;
4235
cristy3ed852e2009-09-05 21:47:34 +00004236 MagickBooleanType
4237 status;
4238
cristye076a6e2010-08-15 19:59:43 +00004239 ssize_t
4240 page_size;
4241
cristy3ed852e2009-09-05 21:47:34 +00004242 assert(image != (Image *) NULL);
4243 assert(image->signature == MagickSignature);
4244 if (image->debug != MagickFalse)
4245 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4246 assert(image->cache != (void *) NULL);
4247 assert(filename != (const char *) NULL);
4248 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004249 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004250 cache_info=(CacheInfo *) image->cache;
4251 assert(cache_info->signature == MagickSignature);
4252 if (attach != MagickFalse)
4253 {
4254 /*
cristy01b7eb02009-09-10 23:10:14 +00004255 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004256 */
4257 if (image->debug != MagickFalse)
4258 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004259 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004260 (void) CopyMagickString(cache_info->cache_filename,filename,
4261 MaxTextExtent);
4262 cache_info->type=DiskCache;
4263 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004264 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004265 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004266 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004267 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004268 }
cristy01b7eb02009-09-10 23:10:14 +00004269 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4270 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004271 {
cristyf84a1932010-01-03 18:00:18 +00004272 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004273 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004274 (cache_info->reference_count == 1))
4275 {
4276 int
4277 status;
4278
4279 /*
cristy01b7eb02009-09-10 23:10:14 +00004280 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004281 */
cristy320684d2011-09-23 14:55:47 +00004282 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004283 if (status == 0)
4284 {
4285 (void) CopyMagickString(cache_info->cache_filename,filename,
4286 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004287 *offset+=cache_info->length+page_size-(cache_info->length %
4288 page_size);
cristyf84a1932010-01-03 18:00:18 +00004289 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004290 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004291 if (image->debug != MagickFalse)
4292 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4293 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004294 return(MagickTrue);
4295 }
4296 }
cristyf84a1932010-01-03 18:00:18 +00004297 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004298 }
4299 /*
cristy01b7eb02009-09-10 23:10:14 +00004300 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004301 */
4302 clone_image=(*image);
4303 clone_info=(CacheInfo *) clone_image.cache;
4304 image->cache=ClonePixelCache(cache_info);
4305 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4306 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4307 cache_info->type=DiskCache;
4308 cache_info->offset=(*offset);
4309 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004310 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004311 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004312 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004313 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004314 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4315 return(status);
4316}
4317
4318/*
4319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4320% %
4321% %
4322% %
cristyc11dace2012-01-24 16:39:46 +00004323+ 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 +00004324% %
4325% %
4326% %
4327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4328%
cristyc11dace2012-01-24 16:39:46 +00004329% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4330% defined by the region rectangle and returns a pointer to the region. This
4331% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004332% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4333% pixels are transferred, otherwise a NULL is returned.
4334%
cristyc11dace2012-01-24 16:39:46 +00004335% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004336%
cristyc11dace2012-01-24 16:39:46 +00004337% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004338% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004339% const MagickBooleanType clone,NexusInfo *nexus_info,
4340% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004341%
4342% A description of each parameter follows:
4343%
4344% o image: the image.
4345%
4346% o x,y,columns,rows: These values define the perimeter of a region of
4347% pixels.
4348%
4349% o nexus_info: the cache nexus to set.
4350%
cristy65dbf172011-10-06 17:32:04 +00004351% o clone: clone the pixel cache.
4352%
cristy3ed852e2009-09-05 21:47:34 +00004353% o exception: return any errors or warnings in this structure.
4354%
4355*/
cristyc11dace2012-01-24 16:39:46 +00004356MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4357 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004358 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004359{
4360 CacheInfo
4361 *cache_info;
4362
4363 MagickOffsetType
4364 offset;
4365
4366 MagickSizeType
4367 number_pixels;
4368
4369 RectangleInfo
4370 region;
4371
4372 /*
4373 Validate pixel cache geometry.
4374 */
cristye7cc7cf2010-09-21 13:26:47 +00004375 assert(image != (const Image *) NULL);
4376 assert(image->signature == MagickSignature);
4377 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004378 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004379 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004380 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004381 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004382 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4383 {
4384 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4385 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004386 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004387 }
cristybb503372010-05-27 20:51:26 +00004388 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4389 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004390 {
4391 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4392 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004393 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004394 }
4395 offset=(MagickOffsetType) y*cache_info->columns+x;
4396 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004397 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004398 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4399 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4400 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004401 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004402 /*
4403 Return pixel cache.
4404 */
4405 region.x=x;
4406 region.y=y;
4407 region.width=columns;
4408 region.height=rows;
4409 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4410}
4411
4412/*
4413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4414% %
4415% %
4416% %
4417+ 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 %
4418% %
4419% %
4420% %
4421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4422%
4423% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4424% defined by the region rectangle and returns a pointer to the region. This
4425% region is subsequently transferred from the pixel cache with
4426% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4427% pixels are transferred, otherwise a NULL is returned.
4428%
4429% The format of the QueueAuthenticPixelsCache() method is:
4430%
cristy4c08aed2011-07-01 19:47:50 +00004431% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004432% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004433% ExceptionInfo *exception)
4434%
4435% A description of each parameter follows:
4436%
4437% o image: the image.
4438%
4439% o x,y,columns,rows: These values define the perimeter of a region of
4440% pixels.
4441%
4442% o exception: return any errors or warnings in this structure.
4443%
4444*/
cristy4c08aed2011-07-01 19:47:50 +00004445static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004446 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004447 ExceptionInfo *exception)
4448{
4449 CacheInfo
4450 *cache_info;
4451
cristy5c9e6f22010-09-17 17:31:01 +00004452 const int
4453 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004454
cristy4c08aed2011-07-01 19:47:50 +00004455 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004456 *q;
cristy4c08aed2011-07-01 19:47:50 +00004457
cristye7cc7cf2010-09-21 13:26:47 +00004458 assert(image != (const Image *) NULL);
4459 assert(image->signature == MagickSignature);
4460 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004461 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004462 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004463 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004464 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004465 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004466 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004467}
4468
4469/*
4470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4471% %
4472% %
4473% %
4474% Q u e u e A u t h e n t i c P i x e l s %
4475% %
4476% %
4477% %
4478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4479%
4480% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004481% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004482% region is returned, otherwise NULL is returned. The returned pointer may
4483% point to a temporary working buffer for the pixels or it may point to the
4484% final location of the pixels in memory.
4485%
4486% Write-only access means that any existing pixel values corresponding to
4487% the region are ignored. This is useful if the initial image is being
4488% created from scratch, or if the existing pixel values are to be
4489% completely replaced without need to refer to their pre-existing values.
4490% The application is free to read and write the pixel buffer returned by
4491% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4492% initialize the pixel array values. Initializing pixel array values is the
4493% application's responsibility.
4494%
4495% Performance is maximized if the selected region is part of one row, or
4496% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004497% pixels in-place (without a copy) if the image is in memory, or in a
4498% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004499% by the user.
4500%
4501% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004502% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4503% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4504% obtain the meta-content (of type void) corresponding to the region.
4505% Once the Quantum (and/or Quantum) array has been updated, the
4506% changes must be saved back to the underlying image using
4507% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004508%
4509% The format of the QueueAuthenticPixels() method is:
4510%
cristy4c08aed2011-07-01 19:47:50 +00004511% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004512% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004513% ExceptionInfo *exception)
4514%
4515% A description of each parameter follows:
4516%
4517% o image: the image.
4518%
4519% o x,y,columns,rows: These values define the perimeter of a region of
4520% pixels.
4521%
4522% o exception: return any errors or warnings in this structure.
4523%
4524*/
cristy4c08aed2011-07-01 19:47:50 +00004525MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004526 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004527 ExceptionInfo *exception)
4528{
4529 CacheInfo
4530 *cache_info;
4531
cristy2036f5c2010-09-19 21:18:17 +00004532 const int
4533 id = GetOpenMPThreadId();
4534
cristy4c08aed2011-07-01 19:47:50 +00004535 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004536 *q;
cristy4c08aed2011-07-01 19:47:50 +00004537
cristy3ed852e2009-09-05 21:47:34 +00004538 assert(image != (Image *) NULL);
4539 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004540 assert(image->cache != (Cache) NULL);
4541 cache_info=(CacheInfo *) image->cache;
4542 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004543 if (cache_info->methods.queue_authentic_pixels_handler !=
4544 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004545 {
cristyacd2ed22011-08-30 01:44:23 +00004546 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004547 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004548 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004549 }
cristy2036f5c2010-09-19 21:18:17 +00004550 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004551 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004552 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004553 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004554}
4555
4556/*
4557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4558% %
4559% %
4560% %
cristy4c08aed2011-07-01 19:47:50 +00004561+ 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 +00004562% %
4563% %
4564% %
4565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4566%
cristy4c08aed2011-07-01 19:47:50 +00004567% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004568% the pixel cache.
4569%
cristy4c08aed2011-07-01 19:47:50 +00004570% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004571%
cristy4c08aed2011-07-01 19:47:50 +00004572% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004573% NexusInfo *nexus_info,ExceptionInfo *exception)
4574%
4575% A description of each parameter follows:
4576%
4577% o cache_info: the pixel cache.
4578%
cristy4c08aed2011-07-01 19:47:50 +00004579% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004580%
4581% o exception: return any errors or warnings in this structure.
4582%
4583*/
cristy4c08aed2011-07-01 19:47:50 +00004584static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004585 NexusInfo *nexus_info,ExceptionInfo *exception)
4586{
4587 MagickOffsetType
4588 count,
4589 offset;
4590
4591 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004592 extent,
4593 length;
cristy3ed852e2009-09-05 21:47:34 +00004594
cristybb503372010-05-27 20:51:26 +00004595 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004596 y;
4597
cristy4c08aed2011-07-01 19:47:50 +00004598 register unsigned char
4599 *restrict q;
4600
cristybb503372010-05-27 20:51:26 +00004601 size_t
cristy3ed852e2009-09-05 21:47:34 +00004602 rows;
4603
cristy4c08aed2011-07-01 19:47:50 +00004604 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004605 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004606 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004607 return(MagickTrue);
4608 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4609 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004610 length=(MagickSizeType) nexus_info->region.width*
4611 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004612 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004613 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004614 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004615 switch (cache_info->type)
4616 {
4617 case MemoryCache:
4618 case MapCache:
4619 {
cristy4c08aed2011-07-01 19:47:50 +00004620 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004621 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004622
4623 /*
cristy4c08aed2011-07-01 19:47:50 +00004624 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004625 */
cristydd341db2010-03-04 19:06:38 +00004626 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004627 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004628 {
cristy48078b12010-09-23 17:11:01 +00004629 length=extent;
cristydd341db2010-03-04 19:06:38 +00004630 rows=1UL;
4631 }
cristy4c08aed2011-07-01 19:47:50 +00004632 p=(unsigned char *) cache_info->metacontent+offset*
4633 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004634 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004635 {
cristy8f036fe2010-09-18 02:02:00 +00004636 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004637 p+=cache_info->metacontent_extent*cache_info->columns;
4638 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004639 }
4640 break;
4641 }
4642 case DiskCache:
4643 {
4644 /*
cristy4c08aed2011-07-01 19:47:50 +00004645 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004646 */
4647 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4648 {
4649 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4650 cache_info->cache_filename);
4651 return(MagickFalse);
4652 }
cristydd341db2010-03-04 19:06:38 +00004653 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004654 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004655 {
cristy48078b12010-09-23 17:11:01 +00004656 length=extent;
cristydd341db2010-03-04 19:06:38 +00004657 rows=1UL;
4658 }
cristy48078b12010-09-23 17:11:01 +00004659 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004660 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004661 {
cristy48078b12010-09-23 17:11:01 +00004662 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004663 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004664 cache_info->metacontent_extent,length,(unsigned char *) q);
4665 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004666 break;
4667 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004668 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004669 }
cristyc11dace2012-01-24 16:39:46 +00004670 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4671 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004672 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004673 {
4674 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4675 cache_info->cache_filename);
4676 return(MagickFalse);
4677 }
4678 break;
4679 }
4680 default:
4681 break;
4682 }
4683 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004684 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004685 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004686 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004687 nexus_info->region.width,(double) nexus_info->region.height,(double)
4688 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004689 return(MagickTrue);
4690}
4691
4692/*
4693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4694% %
4695% %
4696% %
4697+ R e a d P i x e l C a c h e P i x e l s %
4698% %
4699% %
4700% %
4701%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4702%
4703% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4704% cache.
4705%
4706% The format of the ReadPixelCachePixels() method is:
4707%
4708% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4709% NexusInfo *nexus_info,ExceptionInfo *exception)
4710%
4711% A description of each parameter follows:
4712%
4713% o cache_info: the pixel cache.
4714%
4715% o nexus_info: the cache nexus to read the pixels.
4716%
4717% o exception: return any errors or warnings in this structure.
4718%
4719*/
4720static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4721 NexusInfo *nexus_info,ExceptionInfo *exception)
4722{
4723 MagickOffsetType
4724 count,
4725 offset;
4726
4727 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004728 extent,
4729 length;
cristy3ed852e2009-09-05 21:47:34 +00004730
cristy4c08aed2011-07-01 19:47:50 +00004731 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004732 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004733
cristye076a6e2010-08-15 19:59:43 +00004734 register ssize_t
4735 y;
4736
cristybb503372010-05-27 20:51:26 +00004737 size_t
cristy3ed852e2009-09-05 21:47:34 +00004738 rows;
4739
cristy4c08aed2011-07-01 19:47:50 +00004740 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004741 return(MagickTrue);
4742 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4743 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004744 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004745 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004746 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004747 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004748 q=nexus_info->pixels;
4749 switch (cache_info->type)
4750 {
4751 case MemoryCache:
4752 case MapCache:
4753 {
cristy4c08aed2011-07-01 19:47:50 +00004754 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004755 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004756
4757 /*
4758 Read pixels from memory.
4759 */
cristydd341db2010-03-04 19:06:38 +00004760 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004761 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004762 {
cristy48078b12010-09-23 17:11:01 +00004763 length=extent;
cristydd341db2010-03-04 19:06:38 +00004764 rows=1UL;
4765 }
cristyed231572011-07-14 02:18:59 +00004766 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004767 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004768 {
cristy8f036fe2010-09-18 02:02:00 +00004769 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004770 p+=cache_info->number_channels*cache_info->columns;
4771 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004772 }
4773 break;
4774 }
4775 case DiskCache:
4776 {
4777 /*
4778 Read pixels from disk.
4779 */
4780 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4781 {
4782 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4783 cache_info->cache_filename);
4784 return(MagickFalse);
4785 }
cristydd341db2010-03-04 19:06:38 +00004786 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004787 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004788 {
cristy48078b12010-09-23 17:11:01 +00004789 length=extent;
cristydd341db2010-03-04 19:06:38 +00004790 rows=1UL;
4791 }
cristybb503372010-05-27 20:51:26 +00004792 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004793 {
4794 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004795 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004796 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004797 break;
4798 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004799 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004800 }
cristyc11dace2012-01-24 16:39:46 +00004801 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4802 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004803 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004804 {
4805 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4806 cache_info->cache_filename);
4807 return(MagickFalse);
4808 }
4809 break;
4810 }
4811 default:
4812 break;
4813 }
4814 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004815 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004816 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004817 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004818 nexus_info->region.width,(double) nexus_info->region.height,(double)
4819 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004820 return(MagickTrue);
4821}
4822
4823/*
4824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4825% %
4826% %
4827% %
4828+ R e f e r e n c e P i x e l C a c h e %
4829% %
4830% %
4831% %
4832%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4833%
4834% ReferencePixelCache() increments the reference count associated with the
4835% pixel cache returning a pointer to the cache.
4836%
4837% The format of the ReferencePixelCache method is:
4838%
4839% Cache ReferencePixelCache(Cache cache_info)
4840%
4841% A description of each parameter follows:
4842%
4843% o cache_info: the pixel cache.
4844%
4845*/
cristya6577ff2011-09-02 19:54:26 +00004846MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004847{
4848 CacheInfo
4849 *cache_info;
4850
4851 assert(cache != (Cache *) NULL);
4852 cache_info=(CacheInfo *) cache;
4853 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004854 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004855 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004856 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004857 return(cache_info);
4858}
4859
4860/*
4861%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4862% %
4863% %
4864% %
4865+ S e t P i x e l C a c h e M e t h o d s %
4866% %
4867% %
4868% %
4869%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4870%
4871% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4872%
4873% The format of the SetPixelCacheMethods() method is:
4874%
4875% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4876%
4877% A description of each parameter follows:
4878%
4879% o cache: the pixel cache.
4880%
4881% o cache_methods: Specifies a pointer to a CacheMethods structure.
4882%
4883*/
cristya6577ff2011-09-02 19:54:26 +00004884MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004885{
4886 CacheInfo
4887 *cache_info;
4888
4889 GetOneAuthenticPixelFromHandler
4890 get_one_authentic_pixel_from_handler;
4891
4892 GetOneVirtualPixelFromHandler
4893 get_one_virtual_pixel_from_handler;
4894
4895 /*
4896 Set cache pixel methods.
4897 */
4898 assert(cache != (Cache) NULL);
4899 assert(cache_methods != (CacheMethods *) NULL);
4900 cache_info=(CacheInfo *) cache;
4901 assert(cache_info->signature == MagickSignature);
4902 if (cache_info->debug != MagickFalse)
4903 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4904 cache_info->filename);
4905 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4906 cache_info->methods.get_virtual_pixel_handler=
4907 cache_methods->get_virtual_pixel_handler;
4908 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4909 cache_info->methods.destroy_pixel_handler=
4910 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004911 if (cache_methods->get_virtual_metacontent_from_handler !=
4912 (GetVirtualMetacontentFromHandler) NULL)
4913 cache_info->methods.get_virtual_metacontent_from_handler=
4914 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004915 if (cache_methods->get_authentic_pixels_handler !=
4916 (GetAuthenticPixelsHandler) NULL)
4917 cache_info->methods.get_authentic_pixels_handler=
4918 cache_methods->get_authentic_pixels_handler;
4919 if (cache_methods->queue_authentic_pixels_handler !=
4920 (QueueAuthenticPixelsHandler) NULL)
4921 cache_info->methods.queue_authentic_pixels_handler=
4922 cache_methods->queue_authentic_pixels_handler;
4923 if (cache_methods->sync_authentic_pixels_handler !=
4924 (SyncAuthenticPixelsHandler) NULL)
4925 cache_info->methods.sync_authentic_pixels_handler=
4926 cache_methods->sync_authentic_pixels_handler;
4927 if (cache_methods->get_authentic_pixels_from_handler !=
4928 (GetAuthenticPixelsFromHandler) NULL)
4929 cache_info->methods.get_authentic_pixels_from_handler=
4930 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004931 if (cache_methods->get_authentic_metacontent_from_handler !=
4932 (GetAuthenticMetacontentFromHandler) NULL)
4933 cache_info->methods.get_authentic_metacontent_from_handler=
4934 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004935 get_one_virtual_pixel_from_handler=
4936 cache_info->methods.get_one_virtual_pixel_from_handler;
4937 if (get_one_virtual_pixel_from_handler !=
4938 (GetOneVirtualPixelFromHandler) NULL)
4939 cache_info->methods.get_one_virtual_pixel_from_handler=
4940 cache_methods->get_one_virtual_pixel_from_handler;
4941 get_one_authentic_pixel_from_handler=
4942 cache_methods->get_one_authentic_pixel_from_handler;
4943 if (get_one_authentic_pixel_from_handler !=
4944 (GetOneAuthenticPixelFromHandler) NULL)
4945 cache_info->methods.get_one_authentic_pixel_from_handler=
4946 cache_methods->get_one_authentic_pixel_from_handler;
4947}
4948
4949/*
4950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4951% %
4952% %
4953% %
4954+ S e t P i x e l C a c h e N e x u s P i x e l s %
4955% %
4956% %
4957% %
4958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4959%
4960% SetPixelCacheNexusPixels() defines the region of the cache for the
4961% specified cache nexus.
4962%
4963% The format of the SetPixelCacheNexusPixels() method is:
4964%
cristy4c08aed2011-07-01 19:47:50 +00004965% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004966% const RectangleInfo *region,NexusInfo *nexus_info,
4967% ExceptionInfo *exception)
4968%
4969% A description of each parameter follows:
4970%
4971% o image: the image.
4972%
4973% o region: A pointer to the RectangleInfo structure that defines the
4974% region of this particular cache nexus.
4975%
4976% o nexus_info: the cache nexus to set.
4977%
4978% o exception: return any errors or warnings in this structure.
4979%
4980*/
cristyabd6e372010-09-15 19:11:26 +00004981
4982static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4983 NexusInfo *nexus_info,ExceptionInfo *exception)
4984{
4985 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4986 return(MagickFalse);
4987 nexus_info->mapped=MagickFalse;
cristy7dc8ac52012-01-10 20:14:52 +00004988 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004989 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004990 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004991 {
4992 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004993 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004994 nexus_info->length);
4995 }
cristy4c08aed2011-07-01 19:47:50 +00004996 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004997 {
4998 (void) ThrowMagickException(exception,GetMagickModule(),
4999 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5000 cache_info->filename);
5001 return(MagickFalse);
5002 }
5003 return(MagickTrue);
5004}
5005
cristy4c08aed2011-07-01 19:47:50 +00005006static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005007 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5008{
5009 CacheInfo
5010 *cache_info;
5011
5012 MagickBooleanType
5013 status;
5014
cristy3ed852e2009-09-05 21:47:34 +00005015 MagickSizeType
5016 length,
5017 number_pixels;
5018
cristy3ed852e2009-09-05 21:47:34 +00005019 cache_info=(CacheInfo *) image->cache;
5020 assert(cache_info->signature == MagickSignature);
5021 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005022 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005023 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005024 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5025 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005026 {
cristybb503372010-05-27 20:51:26 +00005027 ssize_t
cristybad067a2010-02-15 17:20:55 +00005028 x,
5029 y;
cristy3ed852e2009-09-05 21:47:34 +00005030
cristyeaedf062010-05-29 22:36:02 +00005031 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5032 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005033 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5034 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005035 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005036 ((nexus_info->region.width == cache_info->columns) ||
5037 ((nexus_info->region.width % cache_info->columns) == 0)))))
5038 {
5039 MagickOffsetType
5040 offset;
5041
5042 /*
5043 Pixels are accessed directly from memory.
5044 */
5045 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5046 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005047 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005048 offset;
5049 nexus_info->metacontent=(void *) NULL;
5050 if (cache_info->metacontent_extent != 0)
5051 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5052 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005053 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005054 }
5055 }
5056 /*
5057 Pixels are stored in a cache region until they are synced to the cache.
5058 */
5059 number_pixels=(MagickSizeType) nexus_info->region.width*
5060 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005061 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005062 if (cache_info->metacontent_extent != 0)
5063 length+=number_pixels*cache_info->metacontent_extent;
5064 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005065 {
5066 nexus_info->length=length;
5067 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5068 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005069 {
5070 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005071 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005072 }
cristy3ed852e2009-09-05 21:47:34 +00005073 }
5074 else
5075 if (nexus_info->length != length)
5076 {
5077 RelinquishCacheNexusPixels(nexus_info);
5078 nexus_info->length=length;
5079 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5080 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005081 {
5082 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005083 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005084 }
cristy3ed852e2009-09-05 21:47:34 +00005085 }
5086 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005087 nexus_info->metacontent=(void *) NULL;
5088 if (cache_info->metacontent_extent != 0)
5089 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005090 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005091 return(nexus_info->pixels);
5092}
5093
5094/*
5095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5096% %
5097% %
5098% %
5099% 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 %
5100% %
5101% %
5102% %
5103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5104%
5105% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5106% pixel cache and returns the previous setting. A virtual pixel is any pixel
5107% access that is outside the boundaries of the image cache.
5108%
5109% The format of the SetPixelCacheVirtualMethod() method is:
5110%
5111% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5112% const VirtualPixelMethod virtual_pixel_method)
5113%
5114% A description of each parameter follows:
5115%
5116% o image: the image.
5117%
5118% o virtual_pixel_method: choose the type of virtual pixel.
5119%
5120*/
cristyd1dd6e42011-09-04 01:46:08 +00005121MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005122 const VirtualPixelMethod virtual_pixel_method)
5123{
5124 CacheInfo
5125 *cache_info;
5126
5127 VirtualPixelMethod
5128 method;
5129
5130 assert(image != (Image *) NULL);
5131 assert(image->signature == MagickSignature);
5132 if (image->debug != MagickFalse)
5133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5134 assert(image->cache != (Cache) NULL);
5135 cache_info=(CacheInfo *) image->cache;
5136 assert(cache_info->signature == MagickSignature);
5137 method=cache_info->virtual_pixel_method;
5138 cache_info->virtual_pixel_method=virtual_pixel_method;
5139 return(method);
5140}
5141
5142/*
5143%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5144% %
5145% %
5146% %
5147+ 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 %
5148% %
5149% %
5150% %
5151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152%
5153% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5154% in-memory or disk cache. The method returns MagickTrue if the pixel region
5155% is synced, otherwise MagickFalse.
5156%
5157% The format of the SyncAuthenticPixelCacheNexus() method is:
5158%
5159% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5160% NexusInfo *nexus_info,ExceptionInfo *exception)
5161%
5162% A description of each parameter follows:
5163%
5164% o image: the image.
5165%
5166% o nexus_info: the cache nexus to sync.
5167%
5168% o exception: return any errors or warnings in this structure.
5169%
5170*/
cristya6577ff2011-09-02 19:54:26 +00005171MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005172 NexusInfo *nexus_info,ExceptionInfo *exception)
5173{
5174 CacheInfo
5175 *cache_info;
5176
5177 MagickBooleanType
5178 status;
5179
5180 /*
5181 Transfer pixels to the cache.
5182 */
5183 assert(image != (Image *) NULL);
5184 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005185 if (image->cache == (Cache) NULL)
5186 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5187 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005188 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005189 if (cache_info->type == UndefinedCache)
5190 return(MagickFalse);
5191 if ((image->clip_mask != (Image *) NULL) &&
5192 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5193 return(MagickFalse);
5194 if ((image->mask != (Image *) NULL) &&
5195 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5196 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005197 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005198 return(MagickTrue);
5199 assert(cache_info->signature == MagickSignature);
5200 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005201 if ((cache_info->metacontent_extent != 0) &&
5202 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005203 return(MagickFalse);
5204 return(status);
5205}
5206
5207/*
5208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5209% %
5210% %
5211% %
5212+ S y n c A u t h e n t i c P i x e l C a c h e %
5213% %
5214% %
5215% %
5216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5217%
5218% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5219% or disk cache. The method returns MagickTrue if the pixel region is synced,
5220% otherwise MagickFalse.
5221%
5222% The format of the SyncAuthenticPixelsCache() method is:
5223%
5224% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5225% ExceptionInfo *exception)
5226%
5227% A description of each parameter follows:
5228%
5229% o image: the image.
5230%
5231% o exception: return any errors or warnings in this structure.
5232%
5233*/
5234static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5235 ExceptionInfo *exception)
5236{
5237 CacheInfo
5238 *cache_info;
5239
cristy5c9e6f22010-09-17 17:31:01 +00005240 const int
5241 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005242
cristy4c08aed2011-07-01 19:47:50 +00005243 MagickBooleanType
5244 status;
5245
cristye7cc7cf2010-09-21 13:26:47 +00005246 assert(image != (Image *) NULL);
5247 assert(image->signature == MagickSignature);
5248 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005249 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005250 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005251 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005252 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5253 exception);
5254 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005255}
5256
5257/*
5258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5259% %
5260% %
5261% %
5262% S y n c A u t h e n t i c P i x e l s %
5263% %
5264% %
5265% %
5266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5267%
5268% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5269% The method returns MagickTrue if the pixel region is flushed, otherwise
5270% MagickFalse.
5271%
5272% The format of the SyncAuthenticPixels() method is:
5273%
5274% MagickBooleanType SyncAuthenticPixels(Image *image,
5275% ExceptionInfo *exception)
5276%
5277% A description of each parameter follows:
5278%
5279% o image: the image.
5280%
5281% o exception: return any errors or warnings in this structure.
5282%
5283*/
5284MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5285 ExceptionInfo *exception)
5286{
5287 CacheInfo
5288 *cache_info;
5289
cristy2036f5c2010-09-19 21:18:17 +00005290 const int
5291 id = GetOpenMPThreadId();
5292
cristy4c08aed2011-07-01 19:47:50 +00005293 MagickBooleanType
5294 status;
5295
cristy3ed852e2009-09-05 21:47:34 +00005296 assert(image != (Image *) NULL);
5297 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005298 assert(image->cache != (Cache) NULL);
5299 cache_info=(CacheInfo *) image->cache;
5300 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005301 if (cache_info->methods.sync_authentic_pixels_handler !=
5302 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005303 {
5304 status=cache_info->methods.sync_authentic_pixels_handler(image,
5305 exception);
5306 return(status);
5307 }
cristy2036f5c2010-09-19 21:18:17 +00005308 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005309 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5310 exception);
5311 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005312}
5313
5314/*
5315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5316% %
5317% %
5318% %
cristyd1dd6e42011-09-04 01:46:08 +00005319+ 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 +00005320% %
5321% %
5322% %
5323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5324%
5325% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5326% The method returns MagickTrue if the pixel region is flushed, otherwise
5327% MagickFalse.
5328%
5329% The format of the SyncImagePixelCache() method is:
5330%
5331% MagickBooleanType SyncImagePixelCache(Image *image,
5332% ExceptionInfo *exception)
5333%
5334% A description of each parameter follows:
5335%
5336% o image: the image.
5337%
5338% o exception: return any errors or warnings in this structure.
5339%
5340*/
cristyd1dd6e42011-09-04 01:46:08 +00005341MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005342 ExceptionInfo *exception)
5343{
5344 CacheInfo
5345 *cache_info;
5346
5347 assert(image != (Image *) NULL);
5348 assert(exception != (ExceptionInfo *) NULL);
5349 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5350 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5351}
5352
5353/*
5354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5355% %
5356% %
5357% %
cristy4c08aed2011-07-01 19:47:50 +00005358+ 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 +00005359% %
5360% %
5361% %
5362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5363%
cristy4c08aed2011-07-01 19:47:50 +00005364% WritePixelCacheMetacontent() writes the meta-content to the specified region
5365% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005366%
cristy4c08aed2011-07-01 19:47:50 +00005367% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005368%
cristy4c08aed2011-07-01 19:47:50 +00005369% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005370% NexusInfo *nexus_info,ExceptionInfo *exception)
5371%
5372% A description of each parameter follows:
5373%
5374% o cache_info: the pixel cache.
5375%
cristy4c08aed2011-07-01 19:47:50 +00005376% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005377%
5378% o exception: return any errors or warnings in this structure.
5379%
5380*/
cristy4c08aed2011-07-01 19:47:50 +00005381static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005382 NexusInfo *nexus_info,ExceptionInfo *exception)
5383{
5384 MagickOffsetType
5385 count,
5386 offset;
5387
5388 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005389 extent,
5390 length;
cristy3ed852e2009-09-05 21:47:34 +00005391
cristy4c08aed2011-07-01 19:47:50 +00005392 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005393 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005394
cristybb503372010-05-27 20:51:26 +00005395 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005396 y;
5397
cristybb503372010-05-27 20:51:26 +00005398 size_t
cristy3ed852e2009-09-05 21:47:34 +00005399 rows;
5400
cristy4c08aed2011-07-01 19:47:50 +00005401 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005402 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005403 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005404 return(MagickTrue);
5405 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5406 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005407 length=(MagickSizeType) nexus_info->region.width*
5408 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005409 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005410 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005411 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005412 switch (cache_info->type)
5413 {
5414 case MemoryCache:
5415 case MapCache:
5416 {
cristy4c08aed2011-07-01 19:47:50 +00005417 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005418 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005419
5420 /*
cristy4c08aed2011-07-01 19:47:50 +00005421 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005422 */
cristydd341db2010-03-04 19:06:38 +00005423 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005424 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005425 {
cristy48078b12010-09-23 17:11:01 +00005426 length=extent;
cristydd341db2010-03-04 19:06:38 +00005427 rows=1UL;
5428 }
cristy4c08aed2011-07-01 19:47:50 +00005429 q=(unsigned char *) cache_info->metacontent+offset*
5430 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005431 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005432 {
cristy8f036fe2010-09-18 02:02:00 +00005433 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005434 p+=nexus_info->region.width*cache_info->metacontent_extent;
5435 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005436 }
5437 break;
5438 }
5439 case DiskCache:
5440 {
5441 /*
cristy4c08aed2011-07-01 19:47:50 +00005442 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005443 */
5444 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5445 {
5446 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5447 cache_info->cache_filename);
5448 return(MagickFalse);
5449 }
cristydd341db2010-03-04 19:06:38 +00005450 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005451 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005452 {
cristy48078b12010-09-23 17:11:01 +00005453 length=extent;
cristydd341db2010-03-04 19:06:38 +00005454 rows=1UL;
5455 }
cristy48078b12010-09-23 17:11:01 +00005456 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005457 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005458 {
cristy48078b12010-09-23 17:11:01 +00005459 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005460 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005461 cache_info->metacontent_extent,length,(const unsigned char *) p);
5462 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005463 break;
cristy4c08aed2011-07-01 19:47:50 +00005464 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005465 offset+=cache_info->columns;
5466 }
cristyc11dace2012-01-24 16:39:46 +00005467 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5468 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005469 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005470 {
5471 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5472 cache_info->cache_filename);
5473 return(MagickFalse);
5474 }
5475 break;
5476 }
5477 default:
5478 break;
5479 }
5480 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005481 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005482 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005483 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005484 nexus_info->region.width,(double) nexus_info->region.height,(double)
5485 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005486 return(MagickTrue);
5487}
5488
5489/*
5490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5491% %
5492% %
5493% %
5494+ W r i t e C a c h e P i x e l s %
5495% %
5496% %
5497% %
5498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5499%
5500% WritePixelCachePixels() writes image pixels to the specified region of the
5501% pixel cache.
5502%
5503% The format of the WritePixelCachePixels() method is:
5504%
5505% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5506% NexusInfo *nexus_info,ExceptionInfo *exception)
5507%
5508% A description of each parameter follows:
5509%
5510% o cache_info: the pixel cache.
5511%
5512% o nexus_info: the cache nexus to write the pixels.
5513%
5514% o exception: return any errors or warnings in this structure.
5515%
5516*/
5517static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5518 NexusInfo *nexus_info,ExceptionInfo *exception)
5519{
5520 MagickOffsetType
5521 count,
5522 offset;
5523
5524 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005525 extent,
5526 length;
cristy3ed852e2009-09-05 21:47:34 +00005527
cristy4c08aed2011-07-01 19:47:50 +00005528 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005529 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005530
cristybb503372010-05-27 20:51:26 +00005531 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005532 y;
5533
cristybb503372010-05-27 20:51:26 +00005534 size_t
cristy3ed852e2009-09-05 21:47:34 +00005535 rows;
5536
cristy4c08aed2011-07-01 19:47:50 +00005537 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005538 return(MagickTrue);
5539 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5540 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005541 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005542 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005543 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005544 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005545 p=nexus_info->pixels;
5546 switch (cache_info->type)
5547 {
5548 case MemoryCache:
5549 case MapCache:
5550 {
cristy4c08aed2011-07-01 19:47:50 +00005551 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005552 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005553
5554 /*
5555 Write pixels to memory.
5556 */
cristydd341db2010-03-04 19:06:38 +00005557 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005558 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005559 {
cristy48078b12010-09-23 17:11:01 +00005560 length=extent;
cristydd341db2010-03-04 19:06:38 +00005561 rows=1UL;
5562 }
cristyed231572011-07-14 02:18:59 +00005563 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005564 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005565 {
cristy8f036fe2010-09-18 02:02:00 +00005566 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005567 p+=nexus_info->region.width*cache_info->number_channels;
5568 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005569 }
5570 break;
5571 }
5572 case DiskCache:
5573 {
5574 /*
5575 Write pixels to disk.
5576 */
5577 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5578 {
5579 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5580 cache_info->cache_filename);
5581 return(MagickFalse);
5582 }
cristydd341db2010-03-04 19:06:38 +00005583 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005584 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005585 {
cristy48078b12010-09-23 17:11:01 +00005586 length=extent;
cristydd341db2010-03-04 19:06:38 +00005587 rows=1UL;
5588 }
cristybb503372010-05-27 20:51:26 +00005589 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005590 {
5591 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005592 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005593 p);
5594 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005595 break;
cristyed231572011-07-14 02:18:59 +00005596 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005597 offset+=cache_info->columns;
5598 }
cristyc11dace2012-01-24 16:39:46 +00005599 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5600 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005601 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005602 {
5603 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5604 cache_info->cache_filename);
5605 return(MagickFalse);
5606 }
5607 break;
5608 }
5609 default:
5610 break;
5611 }
5612 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005613 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005614 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005615 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005616 nexus_info->region.width,(double) nexus_info->region.height,(double)
5617 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005618 return(MagickTrue);
5619}