blob: 74318ec0d968f45bd4c23f5acfc506871cd9344d [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% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 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"
cristy3ed852e2009-09-05 21:47:34 +000069#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
cristy4c08aed2011-07-01 19:47:50 +000099 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000100 *cache,
101 *pixels;
102
cristy4c08aed2011-07-01 19:47:50 +0000103 void
104 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
cristy4c08aed2011-07-01 19:47:50 +0000117static const Quantum
cristybb503372010-05-27 20:51:26 +0000118 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000119 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000120 *GetVirtualPixelsCache(const Image *);
121
cristy4c08aed2011-07-01 19:47:50 +0000122static const void
123 *GetVirtualMetacontentFromCache(const Image *);
124
cristy3ed852e2009-09-05 21:47:34 +0000125static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000131 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000134 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
cristy4c08aed2011-07-01 19:47:50 +0000137static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) 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
cristy0a922382011-07-16 15:30:34 +0000188 cache_info=(CacheInfo *) AcquireAlignedMemory(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;
208 if ((cache_resources == (SplayTreeInfo *) NULL) &&
209 (instantiate_cache == MagickFalse))
210 {
cristy4e1dff62009-10-25 20:36:03 +0000211 if (cache_semaphore == (SemaphoreInfo *) NULL)
212 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000213 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000214 if ((cache_resources == (SplayTreeInfo *) NULL) &&
215 (instantiate_cache == MagickFalse))
216 {
217 cache_resources=NewSplayTree((int (*)(const void *,const void *))
218 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
219 instantiate_cache=MagickTrue;
220 }
cristyf84a1932010-01-03 18:00:18 +0000221 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000222 }
223 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
224 return((Cache ) cache_info);
225}
226
227/*
228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229% %
230% %
231% %
232% A c q u i r e P i x e l C a c h e N e x u s %
233% %
234% %
235% %
236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237%
238% AcquirePixelCacheNexus() allocates the NexusInfo structure.
239%
240% The format of the AcquirePixelCacheNexus method is:
241%
cristybb503372010-05-27 20:51:26 +0000242% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000243%
244% A description of each parameter follows:
245%
246% o number_threads: the number of nexus threads.
247%
248*/
cristya6577ff2011-09-02 19:54:26 +0000249MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000250{
cristy3ed852e2009-09-05 21:47:34 +0000251 NexusInfo
252 **nexus_info;
253
cristye076a6e2010-08-15 19:59:43 +0000254 register ssize_t
255 i;
256
cristy0a922382011-07-16 15:30:34 +0000257 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
cristy6a924af2010-09-23 14:02:54 +0000263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000264 if (nexus_info[i] == (NexusInfo *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267 nexus_info[i]->signature=MagickSignature;
268 }
269 return(nexus_info);
270}
271
272/*
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274% %
275% %
276% %
cristyd43a46b2010-01-21 02:13:41 +0000277+ A c q u i r e P i x e l C a c h e P i x e l s %
278% %
279% %
280% %
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282%
283% AcquirePixelCachePixels() returns the pixels associated with the specified
284% image.
285%
286% The format of the AcquirePixelCachePixels() method is:
287%
288% const void *AcquirePixelCachePixels(const Image *image,
289% MagickSizeType *length,ExceptionInfo *exception)
290%
291% A description of each parameter follows:
292%
293% o image: the image.
294%
295% o length: the pixel cache length.
296%
297% o exception: return any errors or warnings in this structure.
298%
299*/
300MagickExport const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
302{
303 CacheInfo
304 *cache_info;
305
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000308 assert(exception != (ExceptionInfo *) NULL);
309 assert(exception->signature == MagickSignature);
310 assert(image->cache != (Cache) NULL);
311 cache_info=(CacheInfo *) image->cache;
312 assert(cache_info->signature == MagickSignature);
313 *length=0;
314 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
315 return((const void *) NULL);
316 *length=cache_info->length;
317 return((const void *) cache_info->pixels);
318}
319
320/*
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322% %
323% %
324% %
cristyf34a1452009-10-24 22:29:27 +0000325+ C a c h e C o m p o n e n t G e n e s i s %
326% %
327% %
328% %
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330%
331% CacheComponentGenesis() instantiates the cache component.
332%
333% The format of the CacheComponentGenesis method is:
334%
335% MagickBooleanType CacheComponentGenesis(void)
336%
337*/
cristy5ff4eaf2011-09-03 01:38:02 +0000338MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000339{
cristy165b6092009-10-26 13:52:10 +0000340 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000341 return(MagickTrue);
342}
343
344/*
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346% %
347% %
348% %
349+ C a c h e C o m p o n e n t T e r m i n u s %
350% %
351% %
352% %
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354%
355% CacheComponentTerminus() destroys the cache component.
356%
357% The format of the CacheComponentTerminus() method is:
358%
359% CacheComponentTerminus(void)
360%
361*/
cristy5ff4eaf2011-09-03 01:38:02 +0000362MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000363{
cristy18b17442009-10-25 18:36:48 +0000364 if (cache_semaphore == (SemaphoreInfo *) NULL)
365 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000366 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000367 if (cache_resources != (SplayTreeInfo *) NULL)
368 cache_resources=DestroySplayTree(cache_resources);
369 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000370 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000371 DestroySemaphoreInfo(&cache_semaphore);
372}
373
374/*
375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376% %
377% %
378% %
cristy3ed852e2009-09-05 21:47:34 +0000379+ C l i p P i x e l C a c h e N e x u s %
380% %
381% %
382% %
383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384%
385% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000386% mask. It returns MagickTrue if the pixel region is clipped, otherwise
387% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000388%
389% The format of the ClipPixelCacheNexus() method is:
390%
391% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
392% ExceptionInfo *exception)
393%
394% A description of each parameter follows:
395%
396% o image: the image.
397%
398% o nexus_info: the cache nexus to clip.
399%
400% o exception: return any errors or warnings in this structure.
401%
402*/
403static MagickBooleanType ClipPixelCacheNexus(Image *image,
404 NexusInfo *nexus_info,ExceptionInfo *exception)
405{
406 CacheInfo
407 *cache_info;
408
409 MagickSizeType
410 number_pixels;
411
412 NexusInfo
413 **clip_nexus,
414 **image_nexus;
415
cristy4c08aed2011-07-01 19:47:50 +0000416 register const Quantum
417 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000418 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000419
cristy4c08aed2011-07-01 19:47:50 +0000420 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000421 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000422
cristye076a6e2010-08-15 19:59:43 +0000423 register ssize_t
424 i;
425
cristy3ed852e2009-09-05 21:47:34 +0000426 /*
427 Apply clip mask.
428 */
429 if (image->debug != MagickFalse)
430 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
431 if (image->clip_mask == (Image *) NULL)
432 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000433 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000434 if (cache_info == (Cache) NULL)
435 return(MagickFalse);
436 image_nexus=AcquirePixelCacheNexus(1);
437 clip_nexus=AcquirePixelCacheNexus(1);
438 if ((image_nexus == (NexusInfo **) NULL) ||
439 (clip_nexus == (NexusInfo **) NULL))
440 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +0000441 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
442 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
443 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000444 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000445 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
446 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
447 nexus_info->region.height,clip_nexus[0],exception);
448 number_pixels=(MagickSizeType) nexus_info->region.width*
449 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000450 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000451 {
cristy4c08aed2011-07-01 19:47:50 +0000452 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000453 break;
cristy4c08aed2011-07-01 19:47:50 +0000454 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
cristy3ed852e2009-09-05 21:47:34 +0000455 {
cristy4c08aed2011-07-01 19:47:50 +0000456 SetPixelRed(image,GetPixelRed(image,p),q);
457 SetPixelGreen(image,GetPixelGreen(image,p),q);
458 SetPixelBlue(image,GetPixelBlue(image,p),q);
459 if (cache_info->colorspace == CMYKColorspace)
460 SetPixelBlack(image,GetPixelBlack(image,p),q);
461 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +0000462 }
cristyed231572011-07-14 02:18:59 +0000463 p+=GetPixelChannels(image);
464 q+=GetPixelChannels(image);
465 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000466 }
467 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
468 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000469 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000470 return(MagickFalse);
471 return(MagickTrue);
472}
473
474/*
475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
476% %
477% %
478% %
479+ C l o n e P i x e l C a c h e %
480% %
481% %
482% %
483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484%
485% ClonePixelCache() clones a pixel cache.
486%
487% The format of the ClonePixelCache() method is:
488%
489% Cache ClonePixelCache(const Cache cache)
490%
491% A description of each parameter follows:
492%
493% o cache: the pixel cache.
494%
495*/
cristya6577ff2011-09-02 19:54:26 +0000496MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000497{
498 CacheInfo
499 *clone_info;
500
501 const CacheInfo
502 *cache_info;
503
504 assert(cache != (const Cache) NULL);
505 cache_info=(const CacheInfo *) cache;
506 assert(cache_info->signature == MagickSignature);
507 if (cache_info->debug != MagickFalse)
508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
509 cache_info->filename);
510 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
511 if (clone_info == (Cache) NULL)
512 return((Cache) NULL);
513 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
514 return((Cache ) clone_info);
515}
516
517/*
518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
519% %
520% %
521% %
cristy60c44a82009-10-07 00:58:49 +0000522+ 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 +0000523% %
524% %
525% %
526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
527% ClonePixelCachePixels() clones the source pixel cache to the destination
528% cache.
529%
530% The format of the ClonePixelCachePixels() method is:
531%
532% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
533% CacheInfo *source_info,ExceptionInfo *exception)
534%
535% A description of each parameter follows:
536%
537% o cache_info: the pixel cache.
538%
539% o source_info: the source pixel cache.
540%
541% o exception: return any errors or warnings in this structure.
542%
543*/
544
545static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
546{
547 int
548 status;
549
cristy5ee247a2010-02-12 15:42:34 +0000550 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000551 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000552 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000553 {
554 status=close(cache_info->file);
555 cache_info->file=(-1);
556 RelinquishMagickResource(FileResource,1);
557 }
cristyf84a1932010-01-03 18:00:18 +0000558 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000559 return(status == -1 ? MagickFalse : MagickTrue);
560}
561
562static void LimitPixelCacheDescriptors(void)
563{
564 register CacheInfo
565 *p,
566 *q;
567
568 /*
569 Limit # of open file descriptors.
570 */
571 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
572 return;
cristyf84a1932010-01-03 18:00:18 +0000573 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000574 if (cache_resources == (SplayTreeInfo *) NULL)
575 {
cristyf84a1932010-01-03 18:00:18 +0000576 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000577 return;
578 }
579 ResetSplayTreeIterator(cache_resources);
580 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
581 while (p != (CacheInfo *) NULL)
582 {
583 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000584 break;
cristy3ed852e2009-09-05 21:47:34 +0000585 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
586 }
587 for (q=p; p != (CacheInfo *) NULL; )
588 {
589 if ((p->type == DiskCache) && (p->file != -1) &&
590 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000591 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000592 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
593 }
594 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000595 {
596 /*
597 Close least recently used cache.
598 */
599 (void) close(q->file);
600 q->file=(-1);
601 }
cristyf84a1932010-01-03 18:00:18 +0000602 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000603}
604
605static inline MagickSizeType MagickMax(const MagickSizeType x,
606 const MagickSizeType y)
607{
608 if (x > y)
609 return(x);
610 return(y);
611}
612
613static inline MagickSizeType MagickMin(const MagickSizeType x,
614 const MagickSizeType y)
615{
616 if (x < y)
617 return(x);
618 return(y);
619}
620
621static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
622 const MapMode mode)
623{
624 int
625 file;
626
627 /*
628 Open pixel cache on disk.
629 */
cristyf84a1932010-01-03 18:00:18 +0000630 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000631 if (cache_info->file != -1)
632 {
cristyf84a1932010-01-03 18:00:18 +0000633 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000634 return(MagickTrue); /* cache already open */
635 }
636 LimitPixelCacheDescriptors();
637 if (*cache_info->cache_filename == '\0')
638 file=AcquireUniqueFileResource(cache_info->cache_filename);
639 else
640 switch (mode)
641 {
642 case ReadMode:
643 {
644 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
645 break;
646 }
647 case WriteMode:
648 {
649 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
650 O_EXCL,S_MODE);
651 if (file == -1)
652 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
653 break;
654 }
655 case IOMode:
656 default:
657 {
658 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
659 O_EXCL,S_MODE);
660 if (file == -1)
661 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
662 break;
663 }
664 }
665 if (file == -1)
666 {
cristyf84a1932010-01-03 18:00:18 +0000667 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000668 return(MagickFalse);
669 }
670 (void) AcquireMagickResource(FileResource,1);
671 cache_info->file=file;
672 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000673 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000674 return(MagickTrue);
675}
676
677static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
678 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000679 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000680{
681 register MagickOffsetType
682 i;
683
684 ssize_t
685 count;
686
cristy08a88202010-03-04 19:18:05 +0000687 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000688#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000689 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000690 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000691 {
cristyf84a1932010-01-03 18:00:18 +0000692 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000693 return((MagickOffsetType) -1);
694 }
695#endif
696 count=0;
697 for (i=0; i < (MagickOffsetType) length; i+=count)
698 {
699#if !defined(MAGICKCORE_HAVE_PREAD)
700 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
701 (MagickSizeType) SSIZE_MAX));
702#else
703 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000704 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000705#endif
706 if (count > 0)
707 continue;
708 count=0;
709 if (errno != EINTR)
710 {
711 i=(-1);
712 break;
713 }
714 }
715#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000716 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000717#endif
718 return(i);
719}
720
721static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
722 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000723 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000724{
725 register MagickOffsetType
726 i;
727
728 ssize_t
729 count;
730
cristy08a88202010-03-04 19:18:05 +0000731 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000732#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000733 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000734 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000735 {
cristyf84a1932010-01-03 18:00:18 +0000736 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000737 return((MagickOffsetType) -1);
738 }
739#endif
740 count=0;
741 for (i=0; i < (MagickOffsetType) length; i+=count)
742 {
743#if !defined(MAGICKCORE_HAVE_PWRITE)
744 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
745 (MagickSizeType) SSIZE_MAX));
746#else
747 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000748 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000749#endif
750 if (count > 0)
751 continue;
752 count=0;
753 if (errno != EINTR)
754 {
755 i=(-1);
756 break;
757 }
758 }
759#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000760 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000761#endif
762 return(i);
763}
764
cristy4c08aed2011-07-01 19:47:50 +0000765static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000766 CacheInfo *cache_info,ExceptionInfo *exception)
767{
768 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000769 count;
cristy3ed852e2009-09-05 21:47:34 +0000770
cristy4c08aed2011-07-01 19:47:50 +0000771 register MagickOffsetType
772 i;
cristye076a6e2010-08-15 19:59:43 +0000773
cristybb503372010-05-27 20:51:26 +0000774 size_t
cristy4c08aed2011-07-01 19:47:50 +0000775 length;
cristy3ed852e2009-09-05 21:47:34 +0000776
cristy4c08aed2011-07-01 19:47:50 +0000777 unsigned char
778 *blob;
779
780 /*
781 Clone pixel cache (both caches on disk).
782 */
cristy3ed852e2009-09-05 21:47:34 +0000783 if (cache_info->debug != MagickFalse)
784 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristy0a922382011-07-16 15:30:34 +0000785 blob=(unsigned char *) AcquireAlignedMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000786 sizeof(*blob));
787 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000788 {
cristy4c08aed2011-07-01 19:47:50 +0000789 (void) ThrowMagickException(exception,GetMagickModule(),
790 ResourceLimitError,"MemoryAllocationFailed","`%s'",
791 cache_info->filename);
792 return(MagickFalse);
793 }
cristy3dedf062011-07-02 14:07:40 +0000794 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000795 {
796 blob=(unsigned char *) RelinquishMagickMemory(blob);
797 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
798 cache_info->cache_filename);
799 return(MagickFalse);
800 }
cristy3dedf062011-07-02 14:07:40 +0000801 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000802 {
803 (void) ClosePixelCacheOnDisk(cache_info);
804 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000805 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
806 clone_info->cache_filename);
807 return(MagickFalse);
808 }
cristy4c08aed2011-07-01 19:47:50 +0000809 count=0;
810 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000811 {
cristy4c08aed2011-07-01 19:47:50 +0000812 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
813 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
814 blob);
815 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000816 {
cristy4c08aed2011-07-01 19:47:50 +0000817 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
818 cache_info->cache_filename);
819 break;
cristy3ed852e2009-09-05 21:47:34 +0000820 }
cristy4c08aed2011-07-01 19:47:50 +0000821 length=(size_t) count;
822 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
823 if ((MagickSizeType) count != length)
824 {
825 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
826 clone_info->cache_filename);
827 break;
828 }
829 }
830 (void) ClosePixelCacheOnDisk(clone_info);
831 (void) ClosePixelCacheOnDisk(cache_info);
832 blob=(unsigned char *) RelinquishMagickMemory(blob);
833 if (i < (MagickOffsetType) cache_info->length)
834 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000835 return(MagickTrue);
836}
837
cristy4c08aed2011-07-01 19:47:50 +0000838static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000839 CacheInfo *cache_info,ExceptionInfo *exception)
840{
841 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000842 count;
cristy3ed852e2009-09-05 21:47:34 +0000843
cristy4c08aed2011-07-01 19:47:50 +0000844 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000845 {
cristy3ed852e2009-09-05 21:47:34 +0000846 /*
cristy4c08aed2011-07-01 19:47:50 +0000847 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000848 */
cristy4c08aed2011-07-01 19:47:50 +0000849 if (cache_info->debug != MagickFalse)
850 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
851 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
852 cache_info->length);
853 return(MagickTrue);
854 }
855 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
856 {
857 /*
858 Clone pixel cache (one cache on disk, one in memory).
859 */
860 if (cache_info->debug != MagickFalse)
861 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
862 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000863 {
cristy4c08aed2011-07-01 19:47:50 +0000864 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000865 cache_info->cache_filename);
866 return(MagickFalse);
867 }
cristy4c08aed2011-07-01 19:47:50 +0000868 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
869 cache_info->length,(unsigned char *) clone_info->pixels);
870 (void) ClosePixelCacheOnDisk(cache_info);
871 if ((MagickSizeType) count != cache_info->length)
872 {
873 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
874 cache_info->cache_filename);
875 return(MagickFalse);
876 }
877 return(MagickTrue);
878 }
879 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
880 {
881 /*
882 Clone pixel cache (one cache on disk, one in memory).
883 */
884 if (clone_info->debug != MagickFalse)
885 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
886 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
887 {
888 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
889 clone_info->cache_filename);
890 return(MagickFalse);
891 }
892 count=WritePixelCacheRegion(clone_info,clone_info->offset,
893 clone_info->length,(unsigned char *) cache_info->pixels);
894 (void) ClosePixelCacheOnDisk(clone_info);
895 if ((MagickSizeType) count != clone_info->length)
896 {
897 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
898 clone_info->cache_filename);
899 return(MagickFalse);
900 }
901 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000902 }
903 /*
cristy4c08aed2011-07-01 19:47:50 +0000904 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000905 */
cristy4c08aed2011-07-01 19:47:50 +0000906 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000907}
908
cristy4c08aed2011-07-01 19:47:50 +0000909static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000910 CacheInfo *cache_info,ExceptionInfo *exception)
911{
cristy4c08aed2011-07-01 19:47:50 +0000912 MagickBooleanType
913 status;
cristy3ed852e2009-09-05 21:47:34 +0000914
cristy4c08aed2011-07-01 19:47:50 +0000915 MagickOffsetType
916 cache_offset,
917 clone_offset,
918 count;
919
920 register ssize_t
921 x;
922
923 size_t
cristy3ed852e2009-09-05 21:47:34 +0000924 length;
925
cristy4c08aed2011-07-01 19:47:50 +0000926 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000927 y;
928
cristy4c08aed2011-07-01 19:47:50 +0000929 unsigned char
930 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000931
cristy4c08aed2011-07-01 19:47:50 +0000932 /*
933 Clone pixel cache (unoptimized).
934 */
cristy3ed852e2009-09-05 21:47:34 +0000935 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000936 {
cristy4c08aed2011-07-01 19:47:50 +0000937 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
938 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
939 else
940 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
941 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
942 else
943 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
944 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
945 else
946 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
947 }
cristyed231572011-07-14 02:18:59 +0000948 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
949 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000950 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristy0a922382011-07-16 15:30:34 +0000951 blob=(unsigned char *) AcquireAlignedMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000952 if (blob == (unsigned char *) NULL)
953 {
954 (void) ThrowMagickException(exception,GetMagickModule(),
955 ResourceLimitError,"MemoryAllocationFailed","`%s'",
956 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000957 return(MagickFalse);
958 }
cristy4c08aed2011-07-01 19:47:50 +0000959 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
960 cache_offset=0;
961 clone_offset=0;
962 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000963 {
cristy4c08aed2011-07-01 19:47:50 +0000964 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000965 {
cristy4c08aed2011-07-01 19:47:50 +0000966 blob=(unsigned char *) RelinquishMagickMemory(blob);
967 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000968 cache_info->cache_filename);
969 return(MagickFalse);
970 }
cristy4c08aed2011-07-01 19:47:50 +0000971 cache_offset=cache_info->offset;
972 }
973 if (clone_info->type == DiskCache)
974 {
cristy3dedf062011-07-02 14:07:40 +0000975 if ((cache_info->type == DiskCache) &&
976 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
977 {
978 (void) ClosePixelCacheOnDisk(clone_info);
979 *clone_info->cache_filename='\0';
980 }
981 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000982 {
cristy4c08aed2011-07-01 19:47:50 +0000983 if (cache_info->type == DiskCache)
984 (void) ClosePixelCacheOnDisk(cache_info);
985 blob=(unsigned char *) RelinquishMagickMemory(blob);
986 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
987 clone_info->cache_filename);
988 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000989 }
cristy4c08aed2011-07-01 19:47:50 +0000990 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000991 }
992 /*
cristy4c08aed2011-07-01 19:47:50 +0000993 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000994 */
cristy4c08aed2011-07-01 19:47:50 +0000995 status=MagickTrue;
996 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000997 {
cristy4c08aed2011-07-01 19:47:50 +0000998 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000999 {
cristy3ed852e2009-09-05 21:47:34 +00001000 /*
cristy4c08aed2011-07-01 19:47:50 +00001001 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001002 */
cristyed231572011-07-14 02:18:59 +00001003 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001004 if (cache_info->type != DiskCache)
1005 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1006 length);
cristy3ed852e2009-09-05 21:47:34 +00001007 else
1008 {
cristy4c08aed2011-07-01 19:47:50 +00001009 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1010 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001011 {
cristy4c08aed2011-07-01 19:47:50 +00001012 status=MagickFalse;
1013 break;
cristy3ed852e2009-09-05 21:47:34 +00001014 }
1015 }
cristy4c08aed2011-07-01 19:47:50 +00001016 cache_offset+=length;
1017 if ((y < (ssize_t) clone_info->rows) &&
1018 (x < (ssize_t) clone_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00001019 {
cristy4c08aed2011-07-01 19:47:50 +00001020 /*
1021 Write a set of pixel channels.
1022 */
cristyed231572011-07-14 02:18:59 +00001023 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001024 if (clone_info->type != DiskCache)
1025 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1026 blob,length);
1027 else
1028 {
cristy208b1002011-08-07 18:51:50 +00001029 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001030 if ((MagickSizeType) count != length)
1031 {
1032 status=MagickFalse;
1033 break;
1034 }
1035 }
1036 clone_offset+=length;
cristy3ed852e2009-09-05 21:47:34 +00001037 }
1038 }
cristyed231572011-07-14 02:18:59 +00001039 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001040 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1041 for ( ; x < (ssize_t) clone_info->columns; x++)
1042 {
1043 /*
1044 Set remaining columns with transparent pixel channels.
1045 */
1046 if (clone_info->type != DiskCache)
1047 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1048 length);
1049 else
1050 {
1051 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1052 if ((MagickSizeType) count != length)
1053 {
1054 status=MagickFalse;
1055 break;
1056 }
1057 }
1058 clone_offset+=length;
1059 }
1060 }
cristyed231572011-07-14 02:18:59 +00001061 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001062 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1063 for ( ; y < (ssize_t) clone_info->rows; y++)
1064 {
1065 /*
1066 Set remaining rows with transparent pixels.
1067 */
1068 for (x=0; x < (ssize_t) clone_info->columns; x++)
1069 {
1070 if (clone_info->type != DiskCache)
1071 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1072 length);
1073 else
1074 {
1075 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1076 if ((MagickSizeType) count != length)
1077 {
1078 status=MagickFalse;
1079 break;
1080 }
1081 }
1082 clone_offset+=length;
1083 }
1084 }
1085 if ((cache_info->metacontent_extent != 0) &&
1086 (clone_info->metacontent_extent != 0))
1087 {
1088 /*
1089 Clone metacontent.
1090 */
1091 for (y=0; y < (ssize_t) cache_info->rows; y++)
1092 {
1093 for (x=0; x < (ssize_t) cache_info->columns; x++)
1094 {
1095 /*
1096 Read a set of metacontent.
1097 */
1098 length=cache_info->metacontent_extent;
1099 if (cache_info->type != DiskCache)
1100 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1101 cache_offset,length);
1102 else
1103 {
1104 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1105 if ((MagickSizeType) count != length)
1106 {
1107 status=MagickFalse;
1108 break;
1109 }
1110 }
1111 cache_offset+=length;
1112 if ((y < (ssize_t) clone_info->rows) &&
1113 (x < (ssize_t) clone_info->columns))
1114 {
1115 /*
1116 Write a set of metacontent.
1117 */
1118 length=clone_info->metacontent_extent;
1119 if (clone_info->type != DiskCache)
1120 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1121 blob,length);
1122 else
1123 {
1124 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1125 blob);
1126 if ((MagickSizeType) count != length)
1127 {
1128 status=MagickFalse;
1129 break;
1130 }
1131 }
1132 clone_offset+=length;
1133 }
1134 }
1135 length=clone_info->metacontent_extent;
1136 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1137 for ( ; x < (ssize_t) clone_info->columns; x++)
1138 {
1139 /*
1140 Set remaining columns with metacontent.
1141 */
1142 if (clone_info->type != DiskCache)
1143 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1144 blob,length);
1145 else
1146 {
cristy208b1002011-08-07 18:51:50 +00001147 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001148 if ((MagickSizeType) count != length)
1149 {
1150 status=MagickFalse;
1151 break;
1152 }
1153 }
1154 clone_offset+=length;
1155 }
1156 }
1157 length=clone_info->metacontent_extent;
1158 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1159 for ( ; y < (ssize_t) clone_info->rows; y++)
1160 {
1161 /*
1162 Set remaining rows with metacontent.
1163 */
1164 for (x=0; x < (ssize_t) clone_info->columns; x++)
1165 {
1166 if (clone_info->type != DiskCache)
1167 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1168 blob,length);
1169 else
1170 {
1171 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1172 if ((MagickSizeType) count != length)
1173 {
1174 status=MagickFalse;
1175 break;
1176 }
1177 }
1178 clone_offset+=length;
1179 }
1180 }
1181 }
1182 if (clone_info->type == DiskCache)
1183 (void) ClosePixelCacheOnDisk(clone_info);
1184 if (cache_info->type == DiskCache)
1185 (void) ClosePixelCacheOnDisk(cache_info);
1186 blob=(unsigned char *) RelinquishMagickMemory(blob);
1187 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001188}
1189
1190static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1191 CacheInfo *cache_info,ExceptionInfo *exception)
1192{
cristy5a7fbfb2010-11-06 16:10:59 +00001193 if (cache_info->type == PingCache)
1194 return(MagickTrue);
cristy4c08aed2011-07-01 19:47:50 +00001195 if ((cache_info->columns == clone_info->columns) &&
1196 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001197 (cache_info->number_channels == clone_info->number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00001198 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1199 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1200 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001201}
1202
1203/*
1204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205% %
1206% %
1207% %
1208+ C l o n e P i x e l C a c h e M e t h o d s %
1209% %
1210% %
1211% %
1212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1213%
1214% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1215% another.
1216%
1217% The format of the ClonePixelCacheMethods() method is:
1218%
1219% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1220%
1221% A description of each parameter follows:
1222%
1223% o clone: Specifies a pointer to a Cache structure.
1224%
1225% o cache: the pixel cache.
1226%
1227*/
cristya6577ff2011-09-02 19:54:26 +00001228MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001229{
1230 CacheInfo
1231 *cache_info,
1232 *source_info;
1233
1234 assert(clone != (Cache) NULL);
1235 source_info=(CacheInfo *) clone;
1236 assert(source_info->signature == MagickSignature);
1237 if (source_info->debug != MagickFalse)
1238 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1239 source_info->filename);
1240 assert(cache != (Cache) NULL);
1241 cache_info=(CacheInfo *) cache;
1242 assert(cache_info->signature == MagickSignature);
1243 source_info->methods=cache_info->methods;
1244}
1245
1246/*
1247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248% %
1249% %
1250% %
1251+ D e s t r o y I m a g e P i x e l C a c h e %
1252% %
1253% %
1254% %
1255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1256%
1257% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1258%
1259% The format of the DestroyImagePixelCache() method is:
1260%
1261% void DestroyImagePixelCache(Image *image)
1262%
1263% A description of each parameter follows:
1264%
1265% o image: the image.
1266%
1267*/
1268static void DestroyImagePixelCache(Image *image)
1269{
1270 assert(image != (Image *) NULL);
1271 assert(image->signature == MagickSignature);
1272 if (image->debug != MagickFalse)
1273 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1274 if (image->cache == (void *) NULL)
1275 return;
1276 image->cache=DestroyPixelCache(image->cache);
1277}
1278
1279/*
1280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1281% %
1282% %
1283% %
1284+ D e s t r o y I m a g e P i x e l s %
1285% %
1286% %
1287% %
1288%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1289%
1290% DestroyImagePixels() deallocates memory associated with the pixel cache.
1291%
1292% The format of the DestroyImagePixels() method is:
1293%
1294% void DestroyImagePixels(Image *image)
1295%
1296% A description of each parameter follows:
1297%
1298% o image: the image.
1299%
1300*/
1301MagickExport void DestroyImagePixels(Image *image)
1302{
1303 CacheInfo
1304 *cache_info;
1305
1306 assert(image != (const Image *) NULL);
1307 assert(image->signature == MagickSignature);
1308 if (image->debug != MagickFalse)
1309 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1310 assert(image->cache != (Cache) NULL);
1311 cache_info=(CacheInfo *) image->cache;
1312 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001313 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1314 {
1315 cache_info->methods.destroy_pixel_handler(image);
1316 return;
1317 }
cristy2036f5c2010-09-19 21:18:17 +00001318 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001319}
1320
1321/*
1322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1323% %
1324% %
1325% %
1326+ D e s t r o y P i x e l C a c h e %
1327% %
1328% %
1329% %
1330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1331%
1332% DestroyPixelCache() deallocates memory associated with the pixel cache.
1333%
1334% The format of the DestroyPixelCache() method is:
1335%
1336% Cache DestroyPixelCache(Cache cache)
1337%
1338% A description of each parameter follows:
1339%
1340% o cache: the pixel cache.
1341%
1342*/
1343
1344static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1345{
1346 switch (cache_info->type)
1347 {
1348 case MemoryCache:
1349 {
1350 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001351 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001352 cache_info->pixels);
1353 else
cristy4c08aed2011-07-01 19:47:50 +00001354 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001355 (size_t) cache_info->length);
1356 RelinquishMagickResource(MemoryResource,cache_info->length);
1357 break;
1358 }
1359 case MapCache:
1360 {
cristy4c08aed2011-07-01 19:47:50 +00001361 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001362 cache_info->length);
1363 RelinquishMagickResource(MapResource,cache_info->length);
1364 }
1365 case DiskCache:
1366 {
1367 if (cache_info->file != -1)
1368 (void) ClosePixelCacheOnDisk(cache_info);
1369 RelinquishMagickResource(DiskResource,cache_info->length);
1370 break;
1371 }
1372 default:
1373 break;
1374 }
1375 cache_info->type=UndefinedCache;
1376 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001377 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001378}
1379
cristya6577ff2011-09-02 19:54:26 +00001380MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001381{
1382 CacheInfo
1383 *cache_info;
1384
cristy3ed852e2009-09-05 21:47:34 +00001385 assert(cache != (Cache) NULL);
1386 cache_info=(CacheInfo *) cache;
1387 assert(cache_info->signature == MagickSignature);
1388 if (cache_info->debug != MagickFalse)
1389 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1390 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001391 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001392 cache_info->reference_count--;
1393 if (cache_info->reference_count != 0)
1394 {
cristyf84a1932010-01-03 18:00:18 +00001395 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001396 return((Cache) NULL);
1397 }
cristyf84a1932010-01-03 18:00:18 +00001398 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001399 if (cache_resources != (SplayTreeInfo *) NULL)
1400 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001401 if (cache_info->debug != MagickFalse)
1402 {
1403 char
1404 message[MaxTextExtent];
1405
cristyb51dff52011-05-19 16:55:47 +00001406 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001407 cache_info->filename);
1408 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1409 }
cristyc2e1bdd2009-09-10 23:43:34 +00001410 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1411 (cache_info->type != DiskCache)))
1412 RelinquishPixelCachePixels(cache_info);
1413 else
1414 {
1415 RelinquishPixelCachePixels(cache_info);
1416 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1417 }
cristy3ed852e2009-09-05 21:47:34 +00001418 *cache_info->cache_filename='\0';
1419 if (cache_info->nexus_info != (NexusInfo **) NULL)
1420 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1421 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001422 if (cache_info->random_info != (RandomInfo *) NULL)
1423 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001424 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1425 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1426 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1427 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001428 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001429 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001430 cache=(Cache) NULL;
1431 return(cache);
1432}
1433
1434/*
1435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1436% %
1437% %
1438% %
1439+ D e s t r o y P i x e l C a c h e N e x u s %
1440% %
1441% %
1442% %
1443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1444%
1445% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1446%
1447% The format of the DestroyPixelCacheNexus() method is:
1448%
1449% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001450% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001451%
1452% A description of each parameter follows:
1453%
1454% o nexus_info: the nexus to destroy.
1455%
1456% o number_threads: the number of nexus threads.
1457%
1458*/
1459
1460static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1461{
1462 if (nexus_info->mapped == MagickFalse)
1463 (void) RelinquishMagickMemory(nexus_info->cache);
1464 else
1465 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001466 nexus_info->cache=(Quantum *) NULL;
1467 nexus_info->pixels=(Quantum *) NULL;
1468 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001469 nexus_info->length=0;
1470 nexus_info->mapped=MagickFalse;
1471}
1472
cristya6577ff2011-09-02 19:54:26 +00001473MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001474 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001475{
cristybb503372010-05-27 20:51:26 +00001476 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001477 i;
1478
1479 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001480 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001481 {
cristy4c08aed2011-07-01 19:47:50 +00001482 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001483 RelinquishCacheNexusPixels(nexus_info[i]);
1484 nexus_info[i]->signature=(~MagickSignature);
cristy0a922382011-07-16 15:30:34 +00001485 nexus_info[i]=(NexusInfo *) RelinquishMagickMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001486 }
cristyb41ee102010-10-04 16:46:15 +00001487 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001488 return(nexus_info);
1489}
1490
1491/*
1492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1493% %
1494% %
1495% %
cristy4c08aed2011-07-01 19:47:50 +00001496% 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 +00001497% %
1498% %
1499% %
1500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1501%
cristy4c08aed2011-07-01 19:47:50 +00001502% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1503% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1504% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001505%
cristy4c08aed2011-07-01 19:47:50 +00001506% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001507%
cristy4c08aed2011-07-01 19:47:50 +00001508% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001509%
1510% A description of each parameter follows:
1511%
1512% o image: the image.
1513%
1514*/
cristy4c08aed2011-07-01 19:47:50 +00001515MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001516{
1517 CacheInfo
1518 *cache_info;
1519
cristy5c9e6f22010-09-17 17:31:01 +00001520 const int
1521 id = GetOpenMPThreadId();
1522
cristy4c08aed2011-07-01 19:47:50 +00001523 void
1524 *metacontent;
1525
cristye7cc7cf2010-09-21 13:26:47 +00001526 assert(image != (const Image *) NULL);
1527 assert(image->signature == MagickSignature);
1528 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001529 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001530 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001531 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1532 (GetAuthenticMetacontentFromHandler) NULL)
1533 {
1534 metacontent=cache_info->methods.
1535 get_authentic_metacontent_from_handler(image);
1536 return(metacontent);
1537 }
cristy6ebe97c2010-07-03 01:17:28 +00001538 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001539 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1540 cache_info->nexus_info[id]);
1541 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001542}
1543
1544/*
1545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546% %
1547% %
1548% %
cristy4c08aed2011-07-01 19:47:50 +00001549+ 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 +00001550% %
1551% %
1552% %
1553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1554%
cristy4c08aed2011-07-01 19:47:50 +00001555% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1556% with the last call to QueueAuthenticPixelsCache() or
1557% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001558%
cristy4c08aed2011-07-01 19:47:50 +00001559% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001560%
cristy4c08aed2011-07-01 19:47:50 +00001561% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001562%
1563% A description of each parameter follows:
1564%
1565% o image: the image.
1566%
1567*/
cristy4c08aed2011-07-01 19:47:50 +00001568static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001569{
1570 CacheInfo
1571 *cache_info;
1572
cristy2036f5c2010-09-19 21:18:17 +00001573 const int
1574 id = GetOpenMPThreadId();
1575
cristy4c08aed2011-07-01 19:47:50 +00001576 void
1577 *metacontent;
1578
cristy3ed852e2009-09-05 21:47:34 +00001579 assert(image != (const Image *) NULL);
1580 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001581 assert(image->cache != (Cache) NULL);
1582 cache_info=(CacheInfo *) image->cache;
1583 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001584 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001585 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1586 cache_info->nexus_info[id]);
1587 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001588}
1589
1590/*
1591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592% %
1593% %
1594% %
1595+ 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 %
1596% %
1597% %
1598% %
1599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1600%
1601% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1602% disk pixel cache as defined by the geometry parameters. A pointer to the
1603% pixels is returned if the pixels are transferred, otherwise a NULL is
1604% returned.
1605%
1606% The format of the GetAuthenticPixelCacheNexus() method is:
1607%
cristy4c08aed2011-07-01 19:47:50 +00001608% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001609% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001610% NexusInfo *nexus_info,ExceptionInfo *exception)
1611%
1612% A description of each parameter follows:
1613%
1614% o image: the image.
1615%
1616% o x,y,columns,rows: These values define the perimeter of a region of
1617% pixels.
1618%
1619% o nexus_info: the cache nexus to return.
1620%
1621% o exception: return any errors or warnings in this structure.
1622%
1623*/
1624
cristy4c08aed2011-07-01 19:47:50 +00001625static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001626 NexusInfo *nexus_info)
1627{
cristy4c08aed2011-07-01 19:47:50 +00001628 MagickBooleanType
1629 status;
1630
cristy3ed852e2009-09-05 21:47:34 +00001631 MagickOffsetType
1632 offset;
1633
cristy73724512010-04-12 14:43:14 +00001634 if (cache_info->type == PingCache)
1635 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001636 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1637 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001638 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001639 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001640 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001641}
1642
cristya6577ff2011-09-02 19:54:26 +00001643MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001644 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001645 NexusInfo *nexus_info,ExceptionInfo *exception)
1646{
1647 CacheInfo
1648 *cache_info;
1649
cristy4c08aed2011-07-01 19:47:50 +00001650 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001651 *q;
cristy3ed852e2009-09-05 21:47:34 +00001652
1653 /*
1654 Transfer pixels from the cache.
1655 */
1656 assert(image != (Image *) NULL);
1657 assert(image->signature == MagickSignature);
cristyacd2ed22011-08-30 01:44:23 +00001658 q=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1659 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001660 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001661 cache_info=(CacheInfo *) image->cache;
1662 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001663 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001664 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001665 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001666 return((Quantum *) NULL);
1667 if (cache_info->metacontent_extent != 0)
1668 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1669 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001670 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001671}
1672
1673/*
1674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675% %
1676% %
1677% %
1678+ 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 %
1679% %
1680% %
1681% %
1682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683%
1684% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1685% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1686%
1687% The format of the GetAuthenticPixelsFromCache() method is:
1688%
cristy4c08aed2011-07-01 19:47:50 +00001689% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001690%
1691% A description of each parameter follows:
1692%
1693% o image: the image.
1694%
1695*/
cristy4c08aed2011-07-01 19:47:50 +00001696static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001697{
1698 CacheInfo
1699 *cache_info;
1700
cristy5c9e6f22010-09-17 17:31:01 +00001701 const int
1702 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001703
cristye7cc7cf2010-09-21 13:26:47 +00001704 assert(image != (const Image *) NULL);
1705 assert(image->signature == MagickSignature);
1706 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001707 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001708 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001709 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001710 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001711}
1712
1713/*
1714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1715% %
1716% %
1717% %
1718% G e t A u t h e n t i c P i x e l Q u e u e %
1719% %
1720% %
1721% %
1722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1723%
cristy4c08aed2011-07-01 19:47:50 +00001724% GetAuthenticPixelQueue() returns the authentic pixels associated
1725% corresponding with the last call to QueueAuthenticPixels() or
1726% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001727%
1728% The format of the GetAuthenticPixelQueue() method is:
1729%
cristy4c08aed2011-07-01 19:47:50 +00001730% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001731%
1732% A description of each parameter follows:
1733%
1734% o image: the image.
1735%
1736*/
cristy4c08aed2011-07-01 19:47:50 +00001737MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001738{
1739 CacheInfo
1740 *cache_info;
1741
cristy2036f5c2010-09-19 21:18:17 +00001742 const int
1743 id = GetOpenMPThreadId();
1744
cristy3ed852e2009-09-05 21:47:34 +00001745 assert(image != (const Image *) NULL);
1746 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001747 assert(image->cache != (Cache) NULL);
1748 cache_info=(CacheInfo *) image->cache;
1749 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001750 if (cache_info->methods.get_authentic_pixels_from_handler !=
1751 (GetAuthenticPixelsFromHandler) NULL)
1752 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001753 assert(id < (int) cache_info->number_threads);
1754 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001755}
1756
1757/*
1758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759% %
1760% %
1761% %
1762% G e t A u t h e n t i c P i x e l s %
1763% %
1764% %
cristy4c08aed2011-07-01 19:47:50 +00001765% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001766%
1767% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001768% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001769% representing the region is returned, otherwise NULL is returned.
1770%
1771% The returned pointer may point to a temporary working copy of the pixels
1772% or it may point to the original pixels in memory. Performance is maximized
1773% if the selected region is part of one row, or one or more full rows, since
1774% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001775% if the image is in memory, or in a memory-mapped file. The returned pointer
1776% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001777%
1778% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001779% Quantum. If the image has corresponding metacontent,call
1780% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1781% meta-content corresponding to the region. Once the Quantum array has
1782% been updated, the changes must be saved back to the underlying image using
1783% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001784%
1785% The format of the GetAuthenticPixels() method is:
1786%
cristy4c08aed2011-07-01 19:47:50 +00001787% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001788% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001789% ExceptionInfo *exception)
1790%
1791% A description of each parameter follows:
1792%
1793% o image: the image.
1794%
1795% o x,y,columns,rows: These values define the perimeter of a region of
1796% pixels.
1797%
1798% o exception: return any errors or warnings in this structure.
1799%
1800*/
cristy4c08aed2011-07-01 19:47:50 +00001801MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001802 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001803 ExceptionInfo *exception)
1804{
1805 CacheInfo
1806 *cache_info;
1807
cristy2036f5c2010-09-19 21:18:17 +00001808 const int
1809 id = GetOpenMPThreadId();
1810
cristy4c08aed2011-07-01 19:47:50 +00001811 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001812 *q;
cristy4c08aed2011-07-01 19:47:50 +00001813
cristy3ed852e2009-09-05 21:47:34 +00001814 assert(image != (Image *) NULL);
1815 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001816 assert(image->cache != (Cache) NULL);
1817 cache_info=(CacheInfo *) image->cache;
1818 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001819 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001820 (GetAuthenticPixelsHandler) NULL)
1821 {
cristyacd2ed22011-08-30 01:44:23 +00001822 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1823 exception);
1824 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001825 }
cristy2036f5c2010-09-19 21:18:17 +00001826 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001827 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001828 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001829 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001830}
1831
1832/*
1833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1834% %
1835% %
1836% %
1837+ G e t A u t h e n t i c P i x e l s C a c h e %
1838% %
1839% %
1840% %
1841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1842%
1843% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1844% as defined by the geometry parameters. A pointer to the pixels is returned
1845% if the pixels are transferred, otherwise a NULL is returned.
1846%
1847% The format of the GetAuthenticPixelsCache() method is:
1848%
cristy4c08aed2011-07-01 19:47:50 +00001849% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001850% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001851% ExceptionInfo *exception)
1852%
1853% A description of each parameter follows:
1854%
1855% o image: the image.
1856%
1857% o x,y,columns,rows: These values define the perimeter of a region of
1858% pixels.
1859%
1860% o exception: return any errors or warnings in this structure.
1861%
1862*/
cristy4c08aed2011-07-01 19:47:50 +00001863static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001864 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001865 ExceptionInfo *exception)
1866{
1867 CacheInfo
1868 *cache_info;
1869
cristy5c9e6f22010-09-17 17:31:01 +00001870 const int
1871 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001872
cristy4c08aed2011-07-01 19:47:50 +00001873 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001874 *q;
cristy4c08aed2011-07-01 19:47:50 +00001875
cristye7cc7cf2010-09-21 13:26:47 +00001876 assert(image != (const Image *) NULL);
1877 assert(image->signature == MagickSignature);
1878 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001879 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001880 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001881 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001882 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001883 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001884 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001885 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001886 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001887}
1888
1889/*
1890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1891% %
1892% %
1893% %
1894+ G e t I m a g e E x t e n t %
1895% %
1896% %
1897% %
1898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1899%
cristy4c08aed2011-07-01 19:47:50 +00001900% GetImageExtent() returns the extent of the pixels associated corresponding
1901% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001902%
1903% The format of the GetImageExtent() method is:
1904%
1905% MagickSizeType GetImageExtent(const Image *image)
1906%
1907% A description of each parameter follows:
1908%
1909% o image: the image.
1910%
1911*/
1912MagickExport MagickSizeType GetImageExtent(const Image *image)
1913{
1914 CacheInfo
1915 *cache_info;
1916
cristy5c9e6f22010-09-17 17:31:01 +00001917 const int
1918 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001919
cristy3ed852e2009-09-05 21:47:34 +00001920 assert(image != (Image *) NULL);
1921 assert(image->signature == MagickSignature);
1922 if (image->debug != MagickFalse)
1923 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1924 assert(image->cache != (Cache) NULL);
1925 cache_info=(CacheInfo *) image->cache;
1926 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001927 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001928 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001929}
1930
1931/*
1932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1933% %
1934% %
1935% %
1936+ G e t I m a g e P i x e l C a c h e %
1937% %
1938% %
1939% %
1940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1941%
1942% GetImagePixelCache() ensures that there is only a single reference to the
1943% pixel cache to be modified, updating the provided cache pointer to point to
1944% a clone of the original pixel cache if necessary.
1945%
1946% The format of the GetImagePixelCache method is:
1947%
1948% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1949% ExceptionInfo *exception)
1950%
1951% A description of each parameter follows:
1952%
1953% o image: the image.
1954%
1955% o clone: any value other than MagickFalse clones the cache pixels.
1956%
1957% o exception: return any errors or warnings in this structure.
1958%
1959*/
cristyaf894d72011-08-06 23:03:10 +00001960
cristy3ed852e2009-09-05 21:47:34 +00001961static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1962{
1963 CacheInfo
1964 *cache_info;
1965
1966 /*
1967 Does the image match the pixel cache morphology?
1968 */
1969 cache_info=(CacheInfo *) image->cache;
1970 if ((image->storage_class != cache_info->storage_class) ||
1971 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001972 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00001973 (image->columns != cache_info->columns) ||
1974 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001975 (image->number_channels != cache_info->number_channels) ||
cristy4c08aed2011-07-01 19:47:50 +00001976 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001977 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1978 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1979 return(MagickFalse);
1980 return(MagickTrue);
1981}
1982
cristycd01fae2011-08-06 23:52:42 +00001983static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1984 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001985{
1986 CacheInfo
1987 *cache_info;
1988
cristy3ed852e2009-09-05 21:47:34 +00001989 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001990 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001991 status;
1992
cristy50a10922010-02-15 18:35:25 +00001993 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001994 cpu_throttle = 0,
1995 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001996 time_limit = 0;
1997
cristy1ea34962010-07-01 19:49:21 +00001998 static time_t
cristy208b1002011-08-07 18:51:50 +00001999 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002000
cristyc4f9f132010-03-04 18:50:01 +00002001 status=MagickTrue;
2002 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002003 if (cpu_throttle == 0)
2004 {
2005 char
2006 *limit;
2007
2008 /*
2009 Set CPU throttle in milleseconds.
2010 */
2011 cpu_throttle=MagickResourceInfinity;
2012 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2013 if (limit == (char *) NULL)
2014 limit=GetPolicyValue("throttle");
2015 if (limit != (char *) NULL)
2016 {
2017 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2018 limit=DestroyString(limit);
2019 }
2020 }
2021 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2022 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002023 if (time_limit == 0)
2024 {
cristy6ebe97c2010-07-03 01:17:28 +00002025 /*
2026 Set the exire time in seconds.
2027 */
cristy1ea34962010-07-01 19:49:21 +00002028 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002029 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002030 }
2031 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002032 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002033 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002034 assert(image->cache != (Cache) NULL);
2035 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002036 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002037 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002038 {
cristyceb55ee2010-11-06 16:05:49 +00002039 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002040 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002041 {
cristyceb55ee2010-11-06 16:05:49 +00002042 Image
2043 clone_image;
2044
2045 CacheInfo
2046 *clone_info;
2047
2048 /*
2049 Clone pixel cache.
2050 */
2051 clone_image=(*image);
2052 clone_image.semaphore=AllocateSemaphoreInfo();
2053 clone_image.reference_count=1;
2054 clone_image.cache=ClonePixelCache(cache_info);
2055 clone_info=(CacheInfo *) clone_image.cache;
2056 status=OpenPixelCache(&clone_image,IOMode,exception);
2057 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002058 {
cristy5a7fbfb2010-11-06 16:10:59 +00002059 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002060 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002061 if (status != MagickFalse)
2062 {
cristy979bf772011-08-08 00:04:15 +00002063 if (cache_info->mode == ReadMode)
2064 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002065 destroy=MagickTrue;
2066 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002067 }
2068 }
cristyceb55ee2010-11-06 16:05:49 +00002069 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002070 }
cristyceb55ee2010-11-06 16:05:49 +00002071 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002072 }
cristy4320e0e2009-09-10 15:00:08 +00002073 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002074 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002075 if (status != MagickFalse)
2076 {
2077 /*
2078 Ensure the image matches the pixel cache morphology.
2079 */
2080 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002081 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002082 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2083 status=OpenPixelCache(image,IOMode,exception);
2084 }
cristyf84a1932010-01-03 18:00:18 +00002085 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002086 if (status == MagickFalse)
2087 return((Cache) NULL);
2088 return(image->cache);
2089}
2090
2091/*
2092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2093% %
2094% %
2095% %
2096% G e t O n e A u t h e n t i c P i x e l %
2097% %
2098% %
2099% %
2100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2101%
2102% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2103% location. The image background color is returned if an error occurs.
2104%
2105% The format of the GetOneAuthenticPixel() method is:
2106%
cristybb503372010-05-27 20:51:26 +00002107% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2108% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002109%
2110% A description of each parameter follows:
2111%
2112% o image: the image.
2113%
2114% o x,y: These values define the location of the pixel to return.
2115%
2116% o pixel: return a pixel at the specified (x,y) location.
2117%
2118% o exception: return any errors or warnings in this structure.
2119%
2120*/
cristyacbbb7c2010-06-30 18:56:48 +00002121MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2122 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002123{
2124 CacheInfo
2125 *cache_info;
2126
cristy4c08aed2011-07-01 19:47:50 +00002127 register Quantum
2128 *q;
cristy2036f5c2010-09-19 21:18:17 +00002129
cristy3ed852e2009-09-05 21:47:34 +00002130 assert(image != (Image *) NULL);
2131 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002132 assert(image->cache != (Cache) NULL);
2133 cache_info=(CacheInfo *) image->cache;
2134 assert(cache_info->signature == MagickSignature);
2135 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002136 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2137 (GetOneAuthenticPixelFromHandler) NULL)
2138 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2139 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002140 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2141 if (q == (Quantum *) NULL)
cristy2036f5c2010-09-19 21:18:17 +00002142 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002143 GetPixelPacket(image,q,pixel);
cristy2036f5c2010-09-19 21:18:17 +00002144 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002145}
2146
2147/*
2148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2149% %
2150% %
2151% %
2152+ 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 %
2153% %
2154% %
2155% %
2156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157%
2158% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2159% location. The image background color is returned if an error occurs.
2160%
2161% The format of the GetOneAuthenticPixelFromCache() method is:
2162%
2163% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002164% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2165% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002166%
2167% A description of each parameter follows:
2168%
2169% o image: the image.
2170%
2171% o x,y: These values define the location of the pixel to return.
2172%
2173% o pixel: return a pixel at the specified (x,y) location.
2174%
2175% o exception: return any errors or warnings in this structure.
2176%
2177*/
2178static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002179 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002180{
cristy098f78c2010-09-23 17:28:44 +00002181 CacheInfo
2182 *cache_info;
2183
2184 const int
2185 id = GetOpenMPThreadId();
2186
cristy4c08aed2011-07-01 19:47:50 +00002187 register Quantum
2188 *q;
cristy3ed852e2009-09-05 21:47:34 +00002189
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);
cristy4c08aed2011-07-01 19:47:50 +00002196 *pixel=image->background_color;
2197 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2198 exception);
2199 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002200 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002201 GetPixelPacket(image,q,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002202 return(MagickTrue);
2203}
2204
2205/*
2206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2207% %
2208% %
2209% %
2210% G e t O n e V i r t u a l M a g i c k P i x e l %
2211% %
2212% %
2213% %
2214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215%
2216% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2217% location. The image background color is returned if an error occurs. If
2218% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2219%
2220% The format of the GetOneVirtualMagickPixel() method is:
2221%
2222% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002223% const ssize_t x,const ssize_t y,PixelInfo *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002224% ExceptionInfo exception)
2225%
2226% A description of each parameter follows:
2227%
2228% o image: the image.
2229%
2230% o x,y: these values define the location of the pixel to return.
2231%
2232% o pixel: return a pixel at the specified (x,y) location.
2233%
2234% o exception: return any errors or warnings in this structure.
2235%
2236*/
2237MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002238 const ssize_t x,const ssize_t y,PixelInfo *pixel,
cristyacbbb7c2010-06-30 18:56:48 +00002239 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002240{
2241 CacheInfo
2242 *cache_info;
2243
cristy0158a4b2010-09-20 13:59:45 +00002244 const int
2245 id = GetOpenMPThreadId();
2246
cristy4c08aed2011-07-01 19:47:50 +00002247 register const Quantum
cristyacd2ed22011-08-30 01:44:23 +00002248 *p;
cristy3ed852e2009-09-05 21:47:34 +00002249
2250 assert(image != (const Image *) NULL);
2251 assert(image->signature == MagickSignature);
2252 assert(image->cache != (Cache) NULL);
2253 cache_info=(CacheInfo *) image->cache;
2254 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002255 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00002256 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002257 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002258 GetPixelInfo(image,pixel);
cristyacd2ed22011-08-30 01:44:23 +00002259 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002260 return(MagickFalse);
cristyacd2ed22011-08-30 01:44:23 +00002261 SetPixelInfo(image,p,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002262 return(MagickTrue);
2263}
2264
2265/*
2266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2267% %
2268% %
2269% %
2270% G e t O n e V i r t u a l M e t h o d P i x e l %
2271% %
2272% %
2273% %
2274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2275%
2276% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2277% location as defined by specified pixel method. The image background color
2278% is returned if an error occurs. If you plan to modify the pixel, use
2279% GetOneAuthenticPixel() instead.
2280%
2281% The format of the GetOneVirtualMethodPixel() method is:
2282%
2283% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002284% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
cristy4c08aed2011-07-01 19:47:50 +00002285% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002286%
2287% A description of each parameter follows:
2288%
2289% o image: the image.
2290%
2291% o virtual_pixel_method: the virtual pixel method.
2292%
2293% o x,y: These values define the location of the pixel to return.
2294%
2295% o pixel: return a pixel at the specified (x,y) location.
2296%
2297% o exception: return any errors or warnings in this structure.
2298%
2299*/
2300MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002301 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002302 PixelPacket *pixel,ExceptionInfo *exception)
2303{
cristy3ed852e2009-09-05 21:47:34 +00002304 CacheInfo
2305 *cache_info;
2306
cristy0158a4b2010-09-20 13:59:45 +00002307 const int
2308 id = GetOpenMPThreadId();
2309
cristy4c08aed2011-07-01 19:47:50 +00002310 const Quantum
2311 *p;
cristy2036f5c2010-09-19 21:18:17 +00002312
cristy3ed852e2009-09-05 21:47:34 +00002313 assert(image != (const Image *) NULL);
2314 assert(image->signature == MagickSignature);
2315 assert(image->cache != (Cache) NULL);
2316 cache_info=(CacheInfo *) image->cache;
2317 assert(cache_info->signature == MagickSignature);
2318 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002319 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2320 (GetOneVirtualPixelFromHandler) NULL)
2321 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2322 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002323 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002324 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002325 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002326 if (p == (const Quantum *) NULL)
cristy2036f5c2010-09-19 21:18:17 +00002327 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002328 GetPixelPacket(image,p,pixel);
2329 if (image->colorspace == CMYKColorspace)
2330 pixel->black=GetPixelBlack(image,p);
cristy2036f5c2010-09-19 21:18:17 +00002331 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002332}
2333
2334/*
2335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2336% %
2337% %
2338% %
2339% G e t O n e V i r t u a l P i x e l %
2340% %
2341% %
2342% %
2343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2344%
2345% GetOneVirtualPixel() returns a single virtual pixel at the specified
2346% (x,y) location. The image background color is returned if an error occurs.
2347% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2348%
2349% The format of the GetOneVirtualPixel() method is:
2350%
cristybb503372010-05-27 20:51:26 +00002351% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2352% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002353%
2354% A description of each parameter follows:
2355%
2356% o image: the image.
2357%
2358% o x,y: These values define the location of the pixel to return.
2359%
2360% o pixel: return a pixel at the specified (x,y) location.
2361%
2362% o exception: return any errors or warnings in this structure.
2363%
2364*/
2365MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002366 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002367{
cristy3ed852e2009-09-05 21:47:34 +00002368 CacheInfo
2369 *cache_info;
2370
cristy0158a4b2010-09-20 13:59:45 +00002371 const int
2372 id = GetOpenMPThreadId();
2373
cristy4c08aed2011-07-01 19:47:50 +00002374 const Quantum
2375 *p;
cristy2036f5c2010-09-19 21:18:17 +00002376
cristy3ed852e2009-09-05 21:47:34 +00002377 assert(image != (const Image *) NULL);
2378 assert(image->signature == MagickSignature);
2379 assert(image->cache != (Cache) NULL);
2380 cache_info=(CacheInfo *) image->cache;
2381 assert(cache_info->signature == MagickSignature);
2382 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002383 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2384 (GetOneVirtualPixelFromHandler) NULL)
2385 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2386 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002387 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002388 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002389 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002390 if (p == (const Quantum *) NULL)
cristy2036f5c2010-09-19 21:18:17 +00002391 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002392 GetPixelPacket(image,p,pixel);
2393 if (image->colorspace == CMYKColorspace)
2394 pixel->black=GetPixelBlack(image,p);
cristy2036f5c2010-09-19 21:18:17 +00002395 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002396}
2397
2398/*
2399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2400% %
2401% %
2402% %
2403+ 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 %
2404% %
2405% %
2406% %
2407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2408%
2409% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2410% specified (x,y) location. The image background color is returned if an
2411% error occurs.
2412%
2413% The format of the GetOneVirtualPixelFromCache() method is:
2414%
2415% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002416% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002417% PixelPacket *pixel,ExceptionInfo *exception)
2418%
2419% A description of each parameter follows:
2420%
2421% o image: the image.
2422%
2423% o virtual_pixel_method: the virtual pixel method.
2424%
2425% o x,y: These values define the location of the pixel to return.
2426%
2427% o pixel: return a pixel at the specified (x,y) location.
2428%
2429% o exception: return any errors or warnings in this structure.
2430%
2431*/
2432static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002433 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002434 PixelPacket *pixel,ExceptionInfo *exception)
2435{
cristy0158a4b2010-09-20 13:59:45 +00002436 CacheInfo
2437 *cache_info;
2438
2439 const int
2440 id = GetOpenMPThreadId();
2441
cristy4c08aed2011-07-01 19:47:50 +00002442 const Quantum
2443 *p;
cristy3ed852e2009-09-05 21:47:34 +00002444
cristye7cc7cf2010-09-21 13:26:47 +00002445 assert(image != (const Image *) NULL);
2446 assert(image->signature == MagickSignature);
2447 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002448 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002449 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002450 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002451 *pixel=image->background_color;
cristy4c08aed2011-07-01 19:47:50 +00002452 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002453 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002454 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002455 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002456 GetPixelPacket(image,p,pixel);
2457 if (image->colorspace == CMYKColorspace)
2458 pixel->black=GetPixelBlack(image,p);
cristy3ed852e2009-09-05 21:47:34 +00002459 return(MagickTrue);
2460}
2461
2462/*
2463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2464% %
2465% %
2466% %
2467+ G e t P i x e l C a c h e C o l o r s p a c e %
2468% %
2469% %
2470% %
2471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2472%
2473% GetPixelCacheColorspace() returns the class type of the pixel cache.
2474%
2475% The format of the GetPixelCacheColorspace() method is:
2476%
2477% Colorspace GetPixelCacheColorspace(Cache cache)
2478%
2479% A description of each parameter follows:
2480%
2481% o cache: the pixel cache.
2482%
2483*/
cristya6577ff2011-09-02 19:54:26 +00002484MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002485{
2486 CacheInfo
2487 *cache_info;
2488
2489 assert(cache != (Cache) NULL);
2490 cache_info=(CacheInfo *) cache;
2491 assert(cache_info->signature == MagickSignature);
2492 if (cache_info->debug != MagickFalse)
2493 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2494 cache_info->filename);
2495 return(cache_info->colorspace);
2496}
2497
2498/*
2499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2500% %
2501% %
2502% %
2503+ G e t P i x e l C a c h e M e t h o d s %
2504% %
2505% %
2506% %
2507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508%
2509% GetPixelCacheMethods() initializes the CacheMethods structure.
2510%
2511% The format of the GetPixelCacheMethods() method is:
2512%
2513% void GetPixelCacheMethods(CacheMethods *cache_methods)
2514%
2515% A description of each parameter follows:
2516%
2517% o cache_methods: Specifies a pointer to a CacheMethods structure.
2518%
2519*/
cristya6577ff2011-09-02 19:54:26 +00002520MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002521{
2522 assert(cache_methods != (CacheMethods *) NULL);
2523 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2524 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2525 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002526 cache_methods->get_virtual_metacontent_from_handler=
2527 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002528 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2529 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002530 cache_methods->get_authentic_metacontent_from_handler=
2531 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002532 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2533 cache_methods->get_one_authentic_pixel_from_handler=
2534 GetOneAuthenticPixelFromCache;
2535 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2536 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2537 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2538}
2539
2540/*
2541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2542% %
2543% %
2544% %
2545+ G e t P i x e l C a c h e N e x u s E x t e n t %
2546% %
2547% %
2548% %
2549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2550%
cristy4c08aed2011-07-01 19:47:50 +00002551% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2552% corresponding with the last call to SetPixelCacheNexusPixels() or
2553% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002554%
2555% The format of the GetPixelCacheNexusExtent() method is:
2556%
2557% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2558% NexusInfo *nexus_info)
2559%
2560% A description of each parameter follows:
2561%
2562% o nexus_info: the nexus info.
2563%
2564*/
cristya6577ff2011-09-02 19:54:26 +00002565MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002566 NexusInfo *nexus_info)
2567{
2568 CacheInfo
2569 *cache_info;
2570
2571 MagickSizeType
2572 extent;
2573
cristye7cc7cf2010-09-21 13:26:47 +00002574 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002575 cache_info=(CacheInfo *) cache;
2576 assert(cache_info->signature == MagickSignature);
2577 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2578 if (extent == 0)
2579 return((MagickSizeType) cache_info->columns*cache_info->rows);
2580 return(extent);
2581}
2582
2583/*
2584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585% %
2586% %
2587% %
cristy4c08aed2011-07-01 19:47:50 +00002588+ 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 +00002589% %
2590% %
2591% %
2592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2593%
cristy4c08aed2011-07-01 19:47:50 +00002594% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2595% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002596%
cristy4c08aed2011-07-01 19:47:50 +00002597% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002598%
cristy4c08aed2011-07-01 19:47:50 +00002599% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002600% NexusInfo *nexus_info)
2601%
2602% A description of each parameter follows:
2603%
2604% o cache: the pixel cache.
2605%
cristy4c08aed2011-07-01 19:47:50 +00002606% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002607%
2608*/
cristya6577ff2011-09-02 19:54:26 +00002609MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002610 NexusInfo *nexus_info)
2611{
2612 CacheInfo
2613 *cache_info;
2614
cristye7cc7cf2010-09-21 13:26:47 +00002615 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002616 cache_info=(CacheInfo *) cache;
2617 assert(cache_info->signature == MagickSignature);
2618 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002619 return((void *) NULL);
2620 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002621}
2622
2623/*
2624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2625% %
2626% %
2627% %
2628+ G e t P i x e l C a c h e N e x u s P i x e l s %
2629% %
2630% %
2631% %
2632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633%
2634% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2635% cache nexus.
2636%
2637% The format of the GetPixelCacheNexusPixels() method is:
2638%
cristy4c08aed2011-07-01 19:47:50 +00002639% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002640% NexusInfo *nexus_info)
2641%
2642% A description of each parameter follows:
2643%
2644% o cache: the pixel cache.
2645%
2646% o nexus_info: the cache nexus to return the pixels.
2647%
2648*/
cristya6577ff2011-09-02 19:54:26 +00002649MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002650 NexusInfo *nexus_info)
2651{
2652 CacheInfo
2653 *cache_info;
2654
cristye7cc7cf2010-09-21 13:26:47 +00002655 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002656 cache_info=(CacheInfo *) cache;
2657 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002658 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002659 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002660 return(nexus_info->pixels);
2661}
2662
2663/*
2664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2665% %
2666% %
2667% %
cristy056ba772010-01-02 23:33:54 +00002668+ G e t P i x e l C a c h e P i x e l s %
2669% %
2670% %
2671% %
2672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2673%
2674% GetPixelCachePixels() returns the pixels associated with the specified image.
2675%
2676% The format of the GetPixelCachePixels() method is:
2677%
cristyf84a1932010-01-03 18:00:18 +00002678% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2679% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002680%
2681% A description of each parameter follows:
2682%
2683% o image: the image.
2684%
2685% o length: the pixel cache length.
2686%
cristyf84a1932010-01-03 18:00:18 +00002687% o exception: return any errors or warnings in this structure.
2688%
cristy056ba772010-01-02 23:33:54 +00002689*/
cristyf84a1932010-01-03 18:00:18 +00002690MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2691 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002692{
2693 CacheInfo
2694 *cache_info;
2695
2696 assert(image != (const Image *) NULL);
2697 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002698 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002699 assert(length != (MagickSizeType *) NULL);
2700 assert(exception != (ExceptionInfo *) NULL);
2701 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002702 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002703 assert(cache_info->signature == MagickSignature);
2704 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002705 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002706 return((void *) NULL);
2707 *length=cache_info->length;
2708 return((void *) cache_info->pixels);
2709}
2710
2711/*
2712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2713% %
2714% %
2715% %
cristyb32b90a2009-09-07 21:45:48 +00002716+ 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 +00002717% %
2718% %
2719% %
2720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2721%
2722% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2723%
2724% The format of the GetPixelCacheStorageClass() method is:
2725%
2726% ClassType GetPixelCacheStorageClass(Cache cache)
2727%
2728% A description of each parameter follows:
2729%
2730% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2731%
2732% o cache: the pixel cache.
2733%
2734*/
cristya6577ff2011-09-02 19:54:26 +00002735MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002736{
2737 CacheInfo
2738 *cache_info;
2739
2740 assert(cache != (Cache) NULL);
2741 cache_info=(CacheInfo *) cache;
2742 assert(cache_info->signature == MagickSignature);
2743 if (cache_info->debug != MagickFalse)
2744 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2745 cache_info->filename);
2746 return(cache_info->storage_class);
2747}
2748
2749/*
2750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2751% %
2752% %
2753% %
cristyb32b90a2009-09-07 21:45:48 +00002754+ G e t P i x e l C a c h e T i l e S i z e %
2755% %
2756% %
2757% %
2758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2759%
2760% GetPixelCacheTileSize() returns the pixel cache tile size.
2761%
2762% The format of the GetPixelCacheTileSize() method is:
2763%
cristybb503372010-05-27 20:51:26 +00002764% void GetPixelCacheTileSize(const Image *image,size_t *width,
2765% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002766%
2767% A description of each parameter follows:
2768%
2769% o image: the image.
2770%
2771% o width: the optimize cache tile width in pixels.
2772%
2773% o height: the optimize cache tile height in pixels.
2774%
2775*/
cristya6577ff2011-09-02 19:54:26 +00002776MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002777 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002778{
cristy4c08aed2011-07-01 19:47:50 +00002779 CacheInfo
2780 *cache_info;
2781
cristyb32b90a2009-09-07 21:45:48 +00002782 assert(image != (Image *) NULL);
2783 assert(image->signature == MagickSignature);
2784 if (image->debug != MagickFalse)
2785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002786 cache_info=(CacheInfo *) image->cache;
2787 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002788 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002789 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002790 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002791 *height=(*width);
2792}
2793
2794/*
2795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796% %
2797% %
2798% %
2799+ G e t P i x e l C a c h e T y p e %
2800% %
2801% %
2802% %
2803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804%
2805% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2806%
2807% The format of the GetPixelCacheType() method is:
2808%
2809% CacheType GetPixelCacheType(const Image *image)
2810%
2811% A description of each parameter follows:
2812%
2813% o image: the image.
2814%
2815*/
cristya6577ff2011-09-02 19:54:26 +00002816MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002817{
2818 CacheInfo
2819 *cache_info;
2820
2821 assert(image != (Image *) NULL);
2822 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002823 assert(image->cache != (Cache) NULL);
2824 cache_info=(CacheInfo *) image->cache;
2825 assert(cache_info->signature == MagickSignature);
2826 return(cache_info->type);
2827}
2828
2829/*
2830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831% %
2832% %
2833% %
cristy3ed852e2009-09-05 21:47:34 +00002834+ 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 %
2835% %
2836% %
2837% %
2838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839%
2840% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2841% pixel cache. A virtual pixel is any pixel access that is outside the
2842% boundaries of the image cache.
2843%
2844% The format of the GetPixelCacheVirtualMethod() method is:
2845%
2846% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2847%
2848% A description of each parameter follows:
2849%
2850% o image: the image.
2851%
2852*/
2853MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2854{
2855 CacheInfo
2856 *cache_info;
2857
2858 assert(image != (Image *) NULL);
2859 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002860 assert(image->cache != (Cache) NULL);
2861 cache_info=(CacheInfo *) image->cache;
2862 assert(cache_info->signature == MagickSignature);
2863 return(cache_info->virtual_pixel_method);
2864}
2865
2866/*
2867%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2868% %
2869% %
2870% %
cristy4c08aed2011-07-01 19:47:50 +00002871+ 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 +00002872% %
2873% %
2874% %
2875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2876%
cristy4c08aed2011-07-01 19:47:50 +00002877% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2878% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002879%
cristy4c08aed2011-07-01 19:47:50 +00002880% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002881%
cristy4c08aed2011-07-01 19:47:50 +00002882% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002883%
2884% A description of each parameter follows:
2885%
2886% o image: the image.
2887%
2888*/
cristy4c08aed2011-07-01 19:47:50 +00002889static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002890{
2891 CacheInfo
2892 *cache_info;
2893
cristy5c9e6f22010-09-17 17:31:01 +00002894 const int
2895 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002896
cristy4c08aed2011-07-01 19:47:50 +00002897 const void
2898 *metacontent;
2899
cristye7cc7cf2010-09-21 13:26:47 +00002900 assert(image != (const Image *) NULL);
2901 assert(image->signature == MagickSignature);
2902 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002903 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002904 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002905 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002906 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2907 cache_info->nexus_info[id]);
2908 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002909}
2910
2911/*
2912%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2913% %
2914% %
2915% %
cristy4c08aed2011-07-01 19:47:50 +00002916+ 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 +00002917% %
2918% %
2919% %
2920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2921%
cristy4c08aed2011-07-01 19:47:50 +00002922% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2923% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002924%
cristy4c08aed2011-07-01 19:47:50 +00002925% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002926%
cristy4c08aed2011-07-01 19:47:50 +00002927% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002928% NexusInfo *nexus_info)
2929%
2930% A description of each parameter follows:
2931%
2932% o cache: the pixel cache.
2933%
cristy4c08aed2011-07-01 19:47:50 +00002934% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002935%
2936*/
cristya6577ff2011-09-02 19:54:26 +00002937MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002938 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002939{
2940 CacheInfo
2941 *cache_info;
2942
cristye7cc7cf2010-09-21 13:26:47 +00002943 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002944 cache_info=(CacheInfo *) cache;
2945 assert(cache_info->signature == MagickSignature);
2946 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002947 return((void *) NULL);
2948 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002949}
2950
2951/*
2952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2953% %
2954% %
2955% %
cristy4c08aed2011-07-01 19:47:50 +00002956% 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 +00002957% %
2958% %
2959% %
2960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2961%
cristy4c08aed2011-07-01 19:47:50 +00002962% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2963% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2964% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002965%
cristy4c08aed2011-07-01 19:47:50 +00002966% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002967%
cristy4c08aed2011-07-01 19:47:50 +00002968% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002969%
2970% A description of each parameter follows:
2971%
2972% o image: the image.
2973%
2974*/
cristy4c08aed2011-07-01 19:47:50 +00002975MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002976{
2977 CacheInfo
2978 *cache_info;
2979
cristy2036f5c2010-09-19 21:18:17 +00002980 const int
2981 id = GetOpenMPThreadId();
2982
cristy4c08aed2011-07-01 19:47:50 +00002983 const void
2984 *metacontent;
2985
cristy3ed852e2009-09-05 21:47:34 +00002986 assert(image != (const Image *) NULL);
2987 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002988 assert(image->cache != (Cache) NULL);
2989 cache_info=(CacheInfo *) image->cache;
2990 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002991 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2992 (GetVirtualMetacontentFromHandler) NULL)
2993 {
2994 metacontent=cache_info->methods.
2995 get_virtual_metacontent_from_handler(image);
2996 return(metacontent);
2997 }
cristy2036f5c2010-09-19 21:18:17 +00002998 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002999 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3000 cache_info->nexus_info[id]);
3001 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003002}
3003
3004/*
3005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3006% %
3007% %
3008% %
3009+ 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 %
3010% %
3011% %
3012% %
3013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3014%
3015% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3016% pixel cache as defined by the geometry parameters. A pointer to the pixels
3017% is returned if the pixels are transferred, otherwise a NULL is returned.
3018%
3019% The format of the GetVirtualPixelsFromNexus() method is:
3020%
cristy4c08aed2011-07-01 19:47:50 +00003021% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003022% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003023% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3024% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003025%
3026% A description of each parameter follows:
3027%
3028% o image: the image.
3029%
3030% o virtual_pixel_method: the virtual pixel method.
3031%
3032% o x,y,columns,rows: These values define the perimeter of a region of
3033% pixels.
3034%
3035% o nexus_info: the cache nexus to acquire.
3036%
3037% o exception: return any errors or warnings in this structure.
3038%
3039*/
3040
cristybb503372010-05-27 20:51:26 +00003041static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003042 DitherMatrix[64] =
3043 {
3044 0, 48, 12, 60, 3, 51, 15, 63,
3045 32, 16, 44, 28, 35, 19, 47, 31,
3046 8, 56, 4, 52, 11, 59, 7, 55,
3047 40, 24, 36, 20, 43, 27, 39, 23,
3048 2, 50, 14, 62, 1, 49, 13, 61,
3049 34, 18, 46, 30, 33, 17, 45, 29,
3050 10, 58, 6, 54, 9, 57, 5, 53,
3051 42, 26, 38, 22, 41, 25, 37, 21
3052 };
3053
cristybb503372010-05-27 20:51:26 +00003054static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003055{
cristybb503372010-05-27 20:51:26 +00003056 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003057 index;
3058
3059 index=x+DitherMatrix[x & 0x07]-32L;
3060 if (index < 0L)
3061 return(0L);
cristybb503372010-05-27 20:51:26 +00003062 if (index >= (ssize_t) columns)
3063 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003064 return(index);
3065}
3066
cristybb503372010-05-27 20:51:26 +00003067static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003068{
cristybb503372010-05-27 20:51:26 +00003069 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003070 index;
3071
3072 index=y+DitherMatrix[y & 0x07]-32L;
3073 if (index < 0L)
3074 return(0L);
cristybb503372010-05-27 20:51:26 +00003075 if (index >= (ssize_t) rows)
3076 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003077 return(index);
3078}
3079
cristybb503372010-05-27 20:51:26 +00003080static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003081{
3082 if (x < 0L)
3083 return(0L);
cristybb503372010-05-27 20:51:26 +00003084 if (x >= (ssize_t) columns)
3085 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003086 return(x);
3087}
3088
cristybb503372010-05-27 20:51:26 +00003089static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003090{
3091 if (y < 0L)
3092 return(0L);
cristybb503372010-05-27 20:51:26 +00003093 if (y >= (ssize_t) rows)
3094 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003095 return(y);
3096}
3097
cristybb503372010-05-27 20:51:26 +00003098static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003099{
cristybb503372010-05-27 20:51:26 +00003100 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003101}
3102
cristybb503372010-05-27 20:51:26 +00003103static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003104{
cristybb503372010-05-27 20:51:26 +00003105 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003106}
3107
cristybb503372010-05-27 20:51:26 +00003108static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3109 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003110{
3111 MagickModulo
3112 modulo;
3113
cristy6162bb42011-07-18 11:34:09 +00003114 /*
3115 Compute the remainder of dividing offset by extent. It returns not only
3116 the quotient (tile the offset falls in) but also the positive remainer
3117 within that tile such that 0 <= remainder < extent. This method is
3118 essentially a ldiv() using a floored modulo division rather than the
3119 normal default truncated modulo division.
3120 */
cristybb503372010-05-27 20:51:26 +00003121 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003122 if (offset < 0L)
3123 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003124 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003125 return(modulo);
3126}
3127
cristya6577ff2011-09-02 19:54:26 +00003128MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003129 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3130 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003131 ExceptionInfo *exception)
3132{
3133 CacheInfo
3134 *cache_info;
3135
3136 MagickOffsetType
3137 offset;
3138
3139 MagickSizeType
3140 length,
3141 number_pixels;
3142
3143 NexusInfo
3144 **virtual_nexus;
3145
cristy4c08aed2011-07-01 19:47:50 +00003146 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003147 *pixels,
cristy105ba3c2011-07-18 02:28:38 +00003148 virtual_pixel[MaxPixelChannels];
cristy3ed852e2009-09-05 21:47:34 +00003149
3150 RectangleInfo
3151 region;
3152
cristy4c08aed2011-07-01 19:47:50 +00003153 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003154 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003155
cristy4c08aed2011-07-01 19:47:50 +00003156 register const void
3157 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003158
cristy4c08aed2011-07-01 19:47:50 +00003159 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003160 *restrict q;
3161
cristybb503372010-05-27 20:51:26 +00003162 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003163 i,
3164 u;
cristy3ed852e2009-09-05 21:47:34 +00003165
cristy4c08aed2011-07-01 19:47:50 +00003166 register unsigned char
3167 *restrict s;
3168
cristy105ba3c2011-07-18 02:28:38 +00003169 ssize_t
3170 v;
3171
cristy4c08aed2011-07-01 19:47:50 +00003172 void
cristy105ba3c2011-07-18 02:28:38 +00003173 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003174
cristy3ed852e2009-09-05 21:47:34 +00003175 /*
3176 Acquire pixels.
3177 */
cristye7cc7cf2010-09-21 13:26:47 +00003178 assert(image != (const Image *) NULL);
3179 assert(image->signature == MagickSignature);
3180 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003181 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003182 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003183 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003184 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003185 region.x=x;
3186 region.y=y;
3187 region.width=columns;
3188 region.height=rows;
3189 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003190 if (pixels == (Quantum *) NULL)
3191 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003192 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003193 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3194 nexus_info->region.x;
3195 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3196 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003197 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3198 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003199 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3200 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003201 {
3202 MagickBooleanType
3203 status;
3204
3205 /*
3206 Pixel request is inside cache extents.
3207 */
cristy4c08aed2011-07-01 19:47:50 +00003208 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003209 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003210 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3211 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003212 return((const Quantum *) NULL);
3213 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003214 {
cristy4c08aed2011-07-01 19:47:50 +00003215 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003216 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003217 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003218 }
cristyacd2ed22011-08-30 01:44:23 +00003219 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003220 }
3221 /*
3222 Pixel request is outside cache extents.
3223 */
cristy4c08aed2011-07-01 19:47:50 +00003224 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003225 virtual_nexus=AcquirePixelCacheNexus(1);
3226 if (virtual_nexus == (NexusInfo **) NULL)
3227 {
cristy4c08aed2011-07-01 19:47:50 +00003228 if (virtual_nexus != (NexusInfo **) NULL)
3229 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003230 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3231 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003232 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003233 }
cristy105ba3c2011-07-18 02:28:38 +00003234 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3235 sizeof(*virtual_pixel));
3236 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003237 switch (virtual_pixel_method)
3238 {
cristy4c08aed2011-07-01 19:47:50 +00003239 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003240 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003241 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003242 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003243 case MaskVirtualPixelMethod:
3244 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003245 case EdgeVirtualPixelMethod:
3246 case CheckerTileVirtualPixelMethod:
3247 case HorizontalTileVirtualPixelMethod:
3248 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003249 {
cristy4c08aed2011-07-01 19:47:50 +00003250 if (cache_info->metacontent_extent != 0)
3251 {
cristy6162bb42011-07-18 11:34:09 +00003252 /*
3253 Acquire a metacontent buffer.
3254 */
cristy105ba3c2011-07-18 02:28:38 +00003255 virtual_metacontent=(void *) AcquireAlignedMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003256 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003257 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003258 {
cristy4c08aed2011-07-01 19:47:50 +00003259 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3260 (void) ThrowMagickException(exception,GetMagickModule(),
3261 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3262 return((const Quantum *) NULL);
3263 }
cristy105ba3c2011-07-18 02:28:38 +00003264 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003265 cache_info->metacontent_extent);
3266 }
3267 switch (virtual_pixel_method)
3268 {
3269 case BlackVirtualPixelMethod:
3270 {
cristy30301712011-07-18 15:06:51 +00003271 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3272 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003273 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3274 break;
3275 }
3276 case GrayVirtualPixelMethod:
3277 {
cristy30301712011-07-18 15:06:51 +00003278 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003279 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3280 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003281 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3282 break;
3283 }
3284 case TransparentVirtualPixelMethod:
3285 {
cristy30301712011-07-18 15:06:51 +00003286 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3287 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003288 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3289 break;
3290 }
3291 case MaskVirtualPixelMethod:
3292 case WhiteVirtualPixelMethod:
3293 {
cristy30301712011-07-18 15:06:51 +00003294 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3295 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003296 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3297 break;
3298 }
3299 default:
3300 {
3301 SetPixelRed(image,image->background_color.red,virtual_pixel);
3302 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3303 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003304 if (image->colorspace == CMYKColorspace)
3305 SetPixelBlack(image,image->background_color.black,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003306 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3307 break;
3308 }
3309 }
cristy3ed852e2009-09-05 21:47:34 +00003310 break;
3311 }
3312 default:
cristy3ed852e2009-09-05 21:47:34 +00003313 break;
cristy3ed852e2009-09-05 21:47:34 +00003314 }
cristybb503372010-05-27 20:51:26 +00003315 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003316 {
cristybb503372010-05-27 20:51:26 +00003317 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003318 {
3319 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003320 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003321 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3322 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003323 {
3324 MagickModulo
3325 x_modulo,
3326 y_modulo;
3327
3328 /*
3329 Transfer a single pixel.
3330 */
3331 length=(MagickSizeType) 1;
3332 switch (virtual_pixel_method)
3333 {
cristy3ed852e2009-09-05 21:47:34 +00003334 default:
3335 {
3336 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003337 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003338 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003339 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003340 break;
3341 }
3342 case RandomVirtualPixelMethod:
3343 {
3344 if (cache_info->random_info == (RandomInfo *) NULL)
3345 cache_info->random_info=AcquireRandomInfo();
3346 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003347 RandomX(cache_info->random_info,cache_info->columns),
3348 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003349 *virtual_nexus,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 DitherVirtualPixelMethod:
3354 {
3355 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003356 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003357 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003358 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003359 break;
3360 }
3361 case TileVirtualPixelMethod:
3362 {
3363 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3364 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3365 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003366 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003367 exception);
cristy4c08aed2011-07-01 19:47:50 +00003368 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003369 break;
3370 }
3371 case MirrorVirtualPixelMethod:
3372 {
3373 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3374 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003375 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003376 x_modulo.remainder-1L;
3377 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3378 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003379 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003380 y_modulo.remainder-1L;
3381 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003382 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003383 exception);
cristy4c08aed2011-07-01 19:47:50 +00003384 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003385 break;
3386 }
3387 case HorizontalTileEdgeVirtualPixelMethod:
3388 {
3389 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3390 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003391 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003392 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003393 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003394 break;
3395 }
3396 case VerticalTileEdgeVirtualPixelMethod:
3397 {
3398 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3399 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003400 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003401 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003402 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3403 break;
3404 }
3405 case BackgroundVirtualPixelMethod:
3406 case BlackVirtualPixelMethod:
3407 case GrayVirtualPixelMethod:
3408 case TransparentVirtualPixelMethod:
3409 case MaskVirtualPixelMethod:
3410 case WhiteVirtualPixelMethod:
3411 {
3412 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003413 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003414 break;
3415 }
3416 case EdgeVirtualPixelMethod:
3417 case CheckerTileVirtualPixelMethod:
3418 {
3419 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3420 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3421 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3422 {
3423 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003424 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003425 break;
3426 }
3427 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3428 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3429 exception);
3430 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3431 break;
3432 }
3433 case HorizontalTileVirtualPixelMethod:
3434 {
3435 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3436 {
3437 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003438 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003439 break;
3440 }
3441 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3442 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3443 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3444 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3445 exception);
3446 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3447 break;
3448 }
3449 case VerticalTileVirtualPixelMethod:
3450 {
3451 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3452 {
3453 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003454 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003455 break;
3456 }
3457 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3458 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3459 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3460 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3461 exception);
3462 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003463 break;
3464 }
3465 }
cristy4c08aed2011-07-01 19:47:50 +00003466 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003467 break;
cristyed231572011-07-14 02:18:59 +00003468 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003469 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003470 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003471 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003472 {
3473 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3474 s+=cache_info->metacontent_extent;
3475 }
cristy3ed852e2009-09-05 21:47:34 +00003476 continue;
3477 }
3478 /*
3479 Transfer a run of pixels.
3480 */
cristy4c08aed2011-07-01 19:47:50 +00003481 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3482 length,1UL,*virtual_nexus,exception);
3483 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003484 break;
cristy4c08aed2011-07-01 19:47:50 +00003485 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003486 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3487 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003488 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003489 {
cristy4c08aed2011-07-01 19:47:50 +00003490 (void) memcpy(s,r,(size_t) length);
3491 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003492 }
3493 }
3494 }
cristy4c08aed2011-07-01 19:47:50 +00003495 /*
3496 Free resources.
3497 */
cristy105ba3c2011-07-18 02:28:38 +00003498 if (virtual_metacontent != (void *) NULL)
3499 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003500 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3501 return(pixels);
3502}
3503
3504/*
3505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3506% %
3507% %
3508% %
3509+ G e t V i r t u a l P i x e l C a c h e %
3510% %
3511% %
3512% %
3513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3514%
3515% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3516% cache as defined by the geometry parameters. A pointer to the pixels
3517% is returned if the pixels are transferred, otherwise a NULL is returned.
3518%
3519% The format of the GetVirtualPixelCache() method is:
3520%
cristy4c08aed2011-07-01 19:47:50 +00003521% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003522% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3523% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003524% ExceptionInfo *exception)
3525%
3526% A description of each parameter follows:
3527%
3528% o image: the image.
3529%
3530% o virtual_pixel_method: the virtual pixel method.
3531%
3532% o x,y,columns,rows: These values define the perimeter of a region of
3533% pixels.
3534%
3535% o exception: return any errors or warnings in this structure.
3536%
3537*/
cristy4c08aed2011-07-01 19:47:50 +00003538static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003539 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3540 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003541{
3542 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003543 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003544
cristy5c9e6f22010-09-17 17:31:01 +00003545 const int
3546 id = GetOpenMPThreadId();
3547
cristy4c08aed2011-07-01 19:47:50 +00003548 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003549 *p;
cristy4c08aed2011-07-01 19:47:50 +00003550
cristye7cc7cf2010-09-21 13:26:47 +00003551 assert(image != (const Image *) NULL);
3552 assert(image->signature == MagickSignature);
3553 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003554 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003555 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003556 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003557 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003558 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003559 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003560}
3561
3562/*
3563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3564% %
3565% %
3566% %
3567% G e t V i r t u a l P i x e l Q u e u e %
3568% %
3569% %
3570% %
3571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3572%
cristy4c08aed2011-07-01 19:47:50 +00003573% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3574% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003575%
3576% The format of the GetVirtualPixelQueue() method is:
3577%
cristy4c08aed2011-07-01 19:47:50 +00003578% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003579%
3580% A description of each parameter follows:
3581%
3582% o image: the image.
3583%
3584*/
cristy4c08aed2011-07-01 19:47:50 +00003585MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003586{
3587 CacheInfo
3588 *cache_info;
3589
cristy2036f5c2010-09-19 21:18:17 +00003590 const int
3591 id = GetOpenMPThreadId();
3592
cristy3ed852e2009-09-05 21:47:34 +00003593 assert(image != (const Image *) NULL);
3594 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003595 assert(image->cache != (Cache) NULL);
3596 cache_info=(CacheInfo *) image->cache;
3597 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003598 if (cache_info->methods.get_virtual_pixels_handler !=
3599 (GetVirtualPixelsHandler) NULL)
3600 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003601 assert(id < (int) cache_info->number_threads);
3602 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003603}
3604
3605/*
3606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3607% %
3608% %
3609% %
3610% G e t V i r t u a l P i x e l s %
3611% %
3612% %
3613% %
3614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3615%
3616% GetVirtualPixels() returns an immutable pixel region. If the
3617% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003618% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003619% copy of the pixels or it may point to the original pixels in memory.
3620% Performance is maximized if the selected region is part of one row, or one
3621% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003622% (without a copy) if the image is in memory, or in a memory-mapped file. The
3623% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003624%
3625% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003626% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3627% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3628% access the meta-content (of type void) corresponding to the the
3629% region.
cristy3ed852e2009-09-05 21:47:34 +00003630%
3631% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3632%
3633% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3634% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3635% GetCacheViewAuthenticPixels() instead.
3636%
3637% The format of the GetVirtualPixels() method is:
3638%
cristy4c08aed2011-07-01 19:47:50 +00003639% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003640% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003641% ExceptionInfo *exception)
3642%
3643% A description of each parameter follows:
3644%
3645% o image: the image.
3646%
3647% o x,y,columns,rows: These values define the perimeter of a region of
3648% pixels.
3649%
3650% o exception: return any errors or warnings in this structure.
3651%
3652*/
cristy4c08aed2011-07-01 19:47:50 +00003653MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003654 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3655 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003656{
3657 CacheInfo
3658 *cache_info;
3659
cristy2036f5c2010-09-19 21:18:17 +00003660 const int
3661 id = GetOpenMPThreadId();
3662
cristy4c08aed2011-07-01 19:47:50 +00003663 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003664 *p;
cristy4c08aed2011-07-01 19:47:50 +00003665
cristy3ed852e2009-09-05 21:47:34 +00003666 assert(image != (const Image *) NULL);
3667 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003668 assert(image->cache != (Cache) NULL);
3669 cache_info=(CacheInfo *) image->cache;
3670 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003671 if (cache_info->methods.get_virtual_pixel_handler !=
3672 (GetVirtualPixelHandler) NULL)
3673 return(cache_info->methods.get_virtual_pixel_handler(image,
3674 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003675 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003676 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003677 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003678 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003679}
3680
3681/*
3682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3683% %
3684% %
3685% %
3686+ 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 %
3687% %
3688% %
3689% %
3690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3691%
cristy4c08aed2011-07-01 19:47:50 +00003692% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3693% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003694%
3695% The format of the GetVirtualPixelsCache() method is:
3696%
cristy4c08aed2011-07-01 19:47:50 +00003697% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003698%
3699% A description of each parameter follows:
3700%
3701% o image: the image.
3702%
3703*/
cristy4c08aed2011-07-01 19:47:50 +00003704static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003705{
3706 CacheInfo
3707 *cache_info;
3708
cristy5c9e6f22010-09-17 17:31:01 +00003709 const int
3710 id = GetOpenMPThreadId();
3711
cristye7cc7cf2010-09-21 13:26:47 +00003712 assert(image != (const Image *) NULL);
3713 assert(image->signature == MagickSignature);
3714 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003715 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003716 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003717 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003718 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003719}
3720
3721/*
3722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3723% %
3724% %
3725% %
3726+ G e t V i r t u a l P i x e l s N e x u s %
3727% %
3728% %
3729% %
3730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3731%
3732% GetVirtualPixelsNexus() returns the pixels associated with the specified
3733% cache nexus.
3734%
3735% The format of the GetVirtualPixelsNexus() method is:
3736%
cristy4c08aed2011-07-01 19:47:50 +00003737% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003738% NexusInfo *nexus_info)
3739%
3740% A description of each parameter follows:
3741%
3742% o cache: the pixel cache.
3743%
3744% o nexus_info: the cache nexus to return the colormap pixels.
3745%
3746*/
cristya6577ff2011-09-02 19:54:26 +00003747MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003748 NexusInfo *nexus_info)
3749{
3750 CacheInfo
3751 *cache_info;
3752
cristye7cc7cf2010-09-21 13:26:47 +00003753 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003754 cache_info=(CacheInfo *) cache;
3755 assert(cache_info->signature == MagickSignature);
3756 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003757 return((Quantum *) NULL);
3758 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003759}
3760
3761/*
3762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3763% %
3764% %
3765% %
3766+ M a s k P i x e l C a c h e N e x u s %
3767% %
3768% %
3769% %
3770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3771%
3772% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3773% The method returns MagickTrue if the pixel region is masked, otherwise
3774% MagickFalse.
3775%
3776% The format of the MaskPixelCacheNexus() method is:
3777%
3778% MagickBooleanType MaskPixelCacheNexus(Image *image,
3779% NexusInfo *nexus_info,ExceptionInfo *exception)
3780%
3781% A description of each parameter follows:
3782%
3783% o image: the image.
3784%
3785% o nexus_info: the cache nexus to clip.
3786%
3787% o exception: return any errors or warnings in this structure.
3788%
3789*/
3790
cristy4c08aed2011-07-01 19:47:50 +00003791static inline void MagickPixelCompositeMask(const PixelInfo *p,
3792 const MagickRealType alpha,const PixelInfo *q,
3793 const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003794{
3795 MagickRealType
3796 gamma;
3797
cristy4c08aed2011-07-01 19:47:50 +00003798 if (alpha == TransparentAlpha)
cristy3ed852e2009-09-05 21:47:34 +00003799 {
3800 *composite=(*q);
3801 return;
3802 }
3803 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3804 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003805 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3806 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3807 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003808 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003809 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003810}
3811
3812static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3813 ExceptionInfo *exception)
3814{
3815 CacheInfo
3816 *cache_info;
3817
cristy4c08aed2011-07-01 19:47:50 +00003818 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003819 alpha,
3820 beta;
3821
3822 MagickSizeType
3823 number_pixels;
3824
3825 NexusInfo
3826 **clip_nexus,
3827 **image_nexus;
3828
cristy4c08aed2011-07-01 19:47:50 +00003829 register const Quantum
3830 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003831 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003832
cristy4c08aed2011-07-01 19:47:50 +00003833 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003834 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003835
cristye076a6e2010-08-15 19:59:43 +00003836 register ssize_t
3837 i;
3838
cristy3ed852e2009-09-05 21:47:34 +00003839 /*
3840 Apply clip mask.
3841 */
3842 if (image->debug != MagickFalse)
3843 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3844 if (image->mask == (Image *) NULL)
3845 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003846 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003847 if (cache_info == (Cache) NULL)
3848 return(MagickFalse);
3849 image_nexus=AcquirePixelCacheNexus(1);
3850 clip_nexus=AcquirePixelCacheNexus(1);
3851 if ((image_nexus == (NexusInfo **) NULL) ||
3852 (clip_nexus == (NexusInfo **) NULL))
3853 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003854 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3855 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3856 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003857 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003858 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3859 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3860 nexus_info->region.height,clip_nexus[0],&image->exception);
cristy4c08aed2011-07-01 19:47:50 +00003861 GetPixelInfo(image,&alpha);
3862 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003863 number_pixels=(MagickSizeType) nexus_info->region.width*
3864 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003865 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003866 {
cristy4c08aed2011-07-01 19:47:50 +00003867 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003868 break;
cristy4c08aed2011-07-01 19:47:50 +00003869 SetPixelInfo(image,p,&alpha);
3870 SetPixelInfo(image,q,&beta);
3871 MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3872 &alpha,alpha.alpha,&beta);
3873 SetPixelRed(image,ClampToQuantum(beta.red),q);
3874 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3875 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3876 if (cache_info->colorspace == CMYKColorspace)
3877 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3878 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003879 p++;
3880 q++;
3881 r++;
3882 }
3883 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3884 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003885 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003886 return(MagickFalse);
3887 return(MagickTrue);
3888}
3889
3890/*
3891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3892% %
3893% %
3894% %
3895+ O p e n P i x e l C a c h e %
3896% %
3897% %
3898% %
3899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3900%
3901% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3902% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003903% metacontent, and memory mapping the cache if it is disk based. The cache
3904% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003905%
3906% The format of the OpenPixelCache() method is:
3907%
3908% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3909% ExceptionInfo *exception)
3910%
3911% A description of each parameter follows:
3912%
3913% o image: the image.
3914%
3915% o mode: ReadMode, WriteMode, or IOMode.
3916%
3917% o exception: return any errors or warnings in this structure.
3918%
3919*/
3920
cristyd43a46b2010-01-21 02:13:41 +00003921static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003922{
3923 cache_info->mapped=MagickFalse;
cristy5e044432011-07-16 03:35:35 +00003924 cache_info->pixels=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003925 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003926 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003927 {
3928 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003929 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003930 cache_info->length);
3931 }
3932}
3933
3934static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3935{
3936 CacheInfo
3937 *cache_info;
3938
3939 MagickOffsetType
3940 count,
3941 extent,
3942 offset;
3943
3944 cache_info=(CacheInfo *) image->cache;
3945 if (image->debug != MagickFalse)
3946 {
3947 char
3948 format[MaxTextExtent],
3949 message[MaxTextExtent];
3950
cristyb9080c92009-12-01 20:13:26 +00003951 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003952 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003953 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003954 cache_info->cache_filename,cache_info->file,format);
3955 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3956 }
3957 if (length != (MagickSizeType) ((MagickOffsetType) length))
3958 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003959 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003960 if (extent < 0)
3961 return(MagickFalse);
3962 if ((MagickSizeType) extent >= length)
3963 return(MagickTrue);
3964 offset=(MagickOffsetType) length-1;
3965 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3966 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3967}
3968
3969static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3970 ExceptionInfo *exception)
3971{
cristy3ed852e2009-09-05 21:47:34 +00003972 CacheInfo
3973 *cache_info,
3974 source_info;
3975
cristyf3a6a9d2010-11-07 21:02:56 +00003976 char
3977 format[MaxTextExtent],
3978 message[MaxTextExtent];
3979
cristy4c08aed2011-07-01 19:47:50 +00003980 MagickBooleanType
3981 status;
3982
cristy3ed852e2009-09-05 21:47:34 +00003983 MagickSizeType
3984 length,
3985 number_pixels;
3986
cristy3ed852e2009-09-05 21:47:34 +00003987 size_t
cristye076a6e2010-08-15 19:59:43 +00003988 columns,
cristy3ed852e2009-09-05 21:47:34 +00003989 packet_size;
3990
cristye7cc7cf2010-09-21 13:26:47 +00003991 assert(image != (const Image *) NULL);
3992 assert(image->signature == MagickSignature);
3993 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003994 if (image->debug != MagickFalse)
3995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3996 if ((image->columns == 0) || (image->rows == 0))
3997 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3998 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003999 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004000 source_info=(*cache_info);
4001 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004002 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004003 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004004 cache_info->storage_class=image->storage_class;
4005 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004006 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004007 cache_info->rows=image->rows;
4008 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004009 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004010 cache_info->number_channels=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00004011 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004012 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004013 if (image->ping != MagickFalse)
4014 {
cristy73724512010-04-12 14:43:14 +00004015 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004016 cache_info->pixels=(Quantum *) NULL;
4017 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004018 cache_info->length=0;
4019 return(MagickTrue);
4020 }
cristy3ed852e2009-09-05 21:47:34 +00004021 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004022 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004023 if (image->metacontent_extent != 0)
4024 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004025 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004026 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004027 if (cache_info->columns != columns)
4028 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4029 image->filename);
4030 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004031 if ((cache_info->type != UndefinedCache) &&
4032 (cache_info->columns <= source_info.columns) &&
4033 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004034 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004035 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4036 {
4037 /*
4038 Inline pixel cache clone optimization.
4039 */
4040 if ((cache_info->columns == source_info.columns) &&
4041 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004042 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004043 (cache_info->metacontent_extent == source_info.metacontent_extent))
4044 return(MagickTrue);
4045 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4046 }
cristy3ed852e2009-09-05 21:47:34 +00004047 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004048 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004049 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004050 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4051 {
4052 status=AcquireMagickResource(MemoryResource,cache_info->length);
4053 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4054 (cache_info->type == MemoryCache))
4055 {
cristyd43a46b2010-01-21 02:13:41 +00004056 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004057 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004058 cache_info->pixels=source_info.pixels;
4059 else
4060 {
4061 /*
4062 Create memory pixel cache.
4063 */
cristy4c08aed2011-07-01 19:47:50 +00004064 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004065 if (image->debug != MagickFalse)
4066 {
cristy97e7a572009-12-05 15:07:53 +00004067 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004068 format);
cristyb51dff52011-05-19 16:55:47 +00004069 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004070 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4071 cache_info->filename,cache_info->mapped != MagickFalse ?
4072 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004073 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004074 format);
cristy3ed852e2009-09-05 21:47:34 +00004075 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4076 message);
4077 }
cristy3ed852e2009-09-05 21:47:34 +00004078 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004079 cache_info->metacontent=(void *) NULL;
4080 if (cache_info->metacontent_extent != 0)
4081 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004082 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004083 if (source_info.storage_class != UndefinedClass)
4084 {
cristy4c08aed2011-07-01 19:47:50 +00004085 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004086 exception);
4087 RelinquishPixelCachePixels(&source_info);
4088 }
cristy4c08aed2011-07-01 19:47:50 +00004089 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004090 }
4091 }
4092 RelinquishMagickResource(MemoryResource,cache_info->length);
4093 }
4094 /*
4095 Create pixel cache on disk.
4096 */
4097 status=AcquireMagickResource(DiskResource,cache_info->length);
4098 if (status == MagickFalse)
4099 {
4100 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4101 "CacheResourcesExhausted","`%s'",image->filename);
4102 return(MagickFalse);
4103 }
4104 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4105 {
4106 RelinquishMagickResource(DiskResource,cache_info->length);
4107 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4108 image->filename);
4109 return(MagickFalse);
4110 }
4111 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4112 cache_info->length);
4113 if (status == MagickFalse)
4114 {
4115 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4116 image->filename);
4117 return(MagickFalse);
4118 }
cristyed231572011-07-14 02:18:59 +00004119 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004120 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004121 status=AcquireMagickResource(AreaResource,cache_info->length);
4122 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4123 cache_info->type=DiskCache;
4124 else
4125 {
4126 status=AcquireMagickResource(MapResource,cache_info->length);
4127 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4128 (cache_info->type != MemoryCache))
4129 cache_info->type=DiskCache;
4130 else
4131 {
cristy4c08aed2011-07-01 19:47:50 +00004132 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004133 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004134 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004135 {
cristy3ed852e2009-09-05 21:47:34 +00004136 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004137 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004138 }
4139 else
4140 {
4141 /*
4142 Create file-backed memory-mapped pixel cache.
4143 */
cristy4c08aed2011-07-01 19:47:50 +00004144 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004145 (void) ClosePixelCacheOnDisk(cache_info);
4146 cache_info->type=MapCache;
4147 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004148 cache_info->metacontent=(void *) NULL;
4149 if (cache_info->metacontent_extent != 0)
4150 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004151 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004152 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004153 {
4154 status=ClonePixelCachePixels(cache_info,&source_info,
4155 exception);
4156 RelinquishPixelCachePixels(&source_info);
4157 }
4158 if (image->debug != MagickFalse)
4159 {
cristy97e7a572009-12-05 15:07:53 +00004160 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004161 format);
cristyb51dff52011-05-19 16:55:47 +00004162 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004163 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004164 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004165 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004166 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004167 format);
cristy3ed852e2009-09-05 21:47:34 +00004168 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4169 message);
4170 }
cristy4c08aed2011-07-01 19:47:50 +00004171 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004172 }
4173 }
4174 RelinquishMagickResource(MapResource,cache_info->length);
4175 }
cristy4c08aed2011-07-01 19:47:50 +00004176 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004177 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4178 {
4179 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4180 RelinquishPixelCachePixels(&source_info);
4181 }
4182 if (image->debug != MagickFalse)
4183 {
cristyb9080c92009-12-01 20:13:26 +00004184 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004185 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004186 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004187 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004188 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004189 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004190 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4191 }
cristy4c08aed2011-07-01 19:47:50 +00004192 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004193}
4194
4195/*
4196%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4197% %
4198% %
4199% %
4200+ P e r s i s t P i x e l C a c h e %
4201% %
4202% %
4203% %
4204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4205%
4206% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4207% persistent pixel cache is one that resides on disk and is not destroyed
4208% when the program exits.
4209%
4210% The format of the PersistPixelCache() method is:
4211%
4212% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4213% const MagickBooleanType attach,MagickOffsetType *offset,
4214% ExceptionInfo *exception)
4215%
4216% A description of each parameter follows:
4217%
4218% o image: the image.
4219%
4220% o filename: the persistent pixel cache filename.
4221%
cristyf3a6a9d2010-11-07 21:02:56 +00004222% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004223%
cristy3ed852e2009-09-05 21:47:34 +00004224% o initialize: A value other than zero initializes the persistent pixel
4225% cache.
4226%
4227% o offset: the offset in the persistent cache to store pixels.
4228%
4229% o exception: return any errors or warnings in this structure.
4230%
4231*/
4232MagickExport MagickBooleanType PersistPixelCache(Image *image,
4233 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4234 ExceptionInfo *exception)
4235{
4236 CacheInfo
4237 *cache_info,
4238 *clone_info;
4239
4240 Image
4241 clone_image;
4242
cristy3ed852e2009-09-05 21:47:34 +00004243 MagickBooleanType
4244 status;
4245
cristye076a6e2010-08-15 19:59:43 +00004246 ssize_t
4247 page_size;
4248
cristy3ed852e2009-09-05 21:47:34 +00004249 assert(image != (Image *) NULL);
4250 assert(image->signature == MagickSignature);
4251 if (image->debug != MagickFalse)
4252 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4253 assert(image->cache != (void *) NULL);
4254 assert(filename != (const char *) NULL);
4255 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004256 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004257 cache_info=(CacheInfo *) image->cache;
4258 assert(cache_info->signature == MagickSignature);
4259 if (attach != MagickFalse)
4260 {
4261 /*
cristy01b7eb02009-09-10 23:10:14 +00004262 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004263 */
4264 if (image->debug != MagickFalse)
4265 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004266 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004267 (void) CopyMagickString(cache_info->cache_filename,filename,
4268 MaxTextExtent);
4269 cache_info->type=DiskCache;
4270 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004271 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004272 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004273 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004274 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004275 }
cristy01b7eb02009-09-10 23:10:14 +00004276 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4277 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004278 {
cristyf84a1932010-01-03 18:00:18 +00004279 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004280 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004281 (cache_info->reference_count == 1))
4282 {
4283 int
4284 status;
4285
4286 /*
cristy01b7eb02009-09-10 23:10:14 +00004287 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004288 */
4289 status=rename(cache_info->cache_filename,filename);
4290 if (status == 0)
4291 {
4292 (void) CopyMagickString(cache_info->cache_filename,filename,
4293 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004294 *offset+=cache_info->length+page_size-(cache_info->length %
4295 page_size);
cristyf84a1932010-01-03 18:00:18 +00004296 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004297 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004298 if (image->debug != MagickFalse)
4299 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4300 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004301 return(MagickTrue);
4302 }
4303 }
cristyf84a1932010-01-03 18:00:18 +00004304 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004305 }
4306 /*
cristy01b7eb02009-09-10 23:10:14 +00004307 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004308 */
4309 clone_image=(*image);
4310 clone_info=(CacheInfo *) clone_image.cache;
4311 image->cache=ClonePixelCache(cache_info);
4312 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4313 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4314 cache_info->type=DiskCache;
4315 cache_info->offset=(*offset);
4316 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004317 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004318 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004319 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004320 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004321 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4322 return(status);
4323}
4324
4325/*
4326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4327% %
4328% %
4329% %
4330+ Q u e u e A u t h e n t i c N e x u s %
4331% %
4332% %
4333% %
4334%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4335%
4336% QueueAuthenticNexus() allocates an region to store image pixels as defined
4337% by the region rectangle and returns a pointer to the region. This region is
4338% subsequently transferred from the pixel cache with
4339% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4340% pixels are transferred, otherwise a NULL is returned.
4341%
4342% The format of the QueueAuthenticNexus() method is:
4343%
cristy4c08aed2011-07-01 19:47:50 +00004344% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004345% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004346% NexusInfo *nexus_info,ExceptionInfo *exception)
4347%
4348% A description of each parameter follows:
4349%
4350% o image: the image.
4351%
4352% o x,y,columns,rows: These values define the perimeter of a region of
4353% pixels.
4354%
4355% o nexus_info: the cache nexus to set.
4356%
4357% o exception: return any errors or warnings in this structure.
4358%
4359*/
cristya6577ff2011-09-02 19:54:26 +00004360MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004361 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4362 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004363{
4364 CacheInfo
4365 *cache_info;
4366
4367 MagickOffsetType
4368 offset;
4369
4370 MagickSizeType
4371 number_pixels;
4372
4373 RectangleInfo
4374 region;
4375
4376 /*
4377 Validate pixel cache geometry.
4378 */
cristye7cc7cf2010-09-21 13:26:47 +00004379 assert(image != (const Image *) NULL);
4380 assert(image->signature == MagickSignature);
4381 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004382 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004383 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004384 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004385 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004386 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4387 {
4388 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4389 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004390 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004391 }
cristybb503372010-05-27 20:51:26 +00004392 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4393 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004394 {
4395 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4396 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004397 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004398 }
4399 offset=(MagickOffsetType) y*cache_info->columns+x;
4400 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004401 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004402 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4403 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4404 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004405 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004406 /*
4407 Return pixel cache.
4408 */
4409 region.x=x;
4410 region.y=y;
4411 region.width=columns;
4412 region.height=rows;
4413 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4414}
4415
4416/*
4417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4418% %
4419% %
4420% %
4421+ 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 %
4422% %
4423% %
4424% %
4425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4426%
4427% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4428% defined by the region rectangle and returns a pointer to the region. This
4429% region is subsequently transferred from the pixel cache with
4430% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4431% pixels are transferred, otherwise a NULL is returned.
4432%
4433% The format of the QueueAuthenticPixelsCache() method is:
4434%
cristy4c08aed2011-07-01 19:47:50 +00004435% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004436% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004437% ExceptionInfo *exception)
4438%
4439% A description of each parameter follows:
4440%
4441% o image: the image.
4442%
4443% o x,y,columns,rows: These values define the perimeter of a region of
4444% pixels.
4445%
4446% o exception: return any errors or warnings in this structure.
4447%
4448*/
cristy4c08aed2011-07-01 19:47:50 +00004449static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004450 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004451 ExceptionInfo *exception)
4452{
4453 CacheInfo
4454 *cache_info;
4455
cristy5c9e6f22010-09-17 17:31:01 +00004456 const int
4457 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004458
cristy4c08aed2011-07-01 19:47:50 +00004459 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004460 *q;
cristy4c08aed2011-07-01 19:47:50 +00004461
cristye7cc7cf2010-09-21 13:26:47 +00004462 assert(image != (const Image *) NULL);
4463 assert(image->signature == MagickSignature);
4464 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004465 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004466 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004467 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00004468 q=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
cristy4c08aed2011-07-01 19:47:50 +00004469 exception);
cristyacd2ed22011-08-30 01:44:23 +00004470 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004471}
4472
4473/*
4474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4475% %
4476% %
4477% %
4478% Q u e u e A u t h e n t i c P i x e l s %
4479% %
4480% %
4481% %
4482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4483%
4484% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004485% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004486% region is returned, otherwise NULL is returned. The returned pointer may
4487% point to a temporary working buffer for the pixels or it may point to the
4488% final location of the pixels in memory.
4489%
4490% Write-only access means that any existing pixel values corresponding to
4491% the region are ignored. This is useful if the initial image is being
4492% created from scratch, or if the existing pixel values are to be
4493% completely replaced without need to refer to their pre-existing values.
4494% The application is free to read and write the pixel buffer returned by
4495% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4496% initialize the pixel array values. Initializing pixel array values is the
4497% application's responsibility.
4498%
4499% Performance is maximized if the selected region is part of one row, or
4500% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004501% pixels in-place (without a copy) if the image is in memory, or in a
4502% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004503% by the user.
4504%
4505% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004506% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4507% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4508% obtain the meta-content (of type void) corresponding to the region.
4509% Once the Quantum (and/or Quantum) array has been updated, the
4510% changes must be saved back to the underlying image using
4511% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004512%
4513% The format of the QueueAuthenticPixels() method is:
4514%
cristy4c08aed2011-07-01 19:47:50 +00004515% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004516% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004517% ExceptionInfo *exception)
4518%
4519% A description of each parameter follows:
4520%
4521% o image: the image.
4522%
4523% o x,y,columns,rows: These values define the perimeter of a region of
4524% pixels.
4525%
4526% o exception: return any errors or warnings in this structure.
4527%
4528*/
cristy4c08aed2011-07-01 19:47:50 +00004529MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004530 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004531 ExceptionInfo *exception)
4532{
4533 CacheInfo
4534 *cache_info;
4535
cristy2036f5c2010-09-19 21:18:17 +00004536 const int
4537 id = GetOpenMPThreadId();
4538
cristy4c08aed2011-07-01 19:47:50 +00004539 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004540 *q;
cristy4c08aed2011-07-01 19:47:50 +00004541
cristy3ed852e2009-09-05 21:47:34 +00004542 assert(image != (Image *) NULL);
4543 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004544 assert(image->cache != (Cache) NULL);
4545 cache_info=(CacheInfo *) image->cache;
4546 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004547 if (cache_info->methods.queue_authentic_pixels_handler !=
4548 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004549 {
cristyacd2ed22011-08-30 01:44:23 +00004550 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004551 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004552 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004553 }
cristy2036f5c2010-09-19 21:18:17 +00004554 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00004555 q=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
cristy4c08aed2011-07-01 19:47:50 +00004556 exception);
cristyacd2ed22011-08-30 01:44:23 +00004557 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004558}
4559
4560/*
4561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4562% %
4563% %
4564% %
cristy4c08aed2011-07-01 19:47:50 +00004565+ 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 +00004566% %
4567% %
4568% %
4569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4570%
cristy4c08aed2011-07-01 19:47:50 +00004571% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004572% the pixel cache.
4573%
cristy4c08aed2011-07-01 19:47:50 +00004574% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004575%
cristy4c08aed2011-07-01 19:47:50 +00004576% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004577% NexusInfo *nexus_info,ExceptionInfo *exception)
4578%
4579% A description of each parameter follows:
4580%
4581% o cache_info: the pixel cache.
4582%
cristy4c08aed2011-07-01 19:47:50 +00004583% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004584%
4585% o exception: return any errors or warnings in this structure.
4586%
4587*/
cristy4c08aed2011-07-01 19:47:50 +00004588static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004589 NexusInfo *nexus_info,ExceptionInfo *exception)
4590{
4591 MagickOffsetType
4592 count,
4593 offset;
4594
4595 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004596 extent,
4597 length;
cristy3ed852e2009-09-05 21:47:34 +00004598
cristybb503372010-05-27 20:51:26 +00004599 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004600 y;
4601
cristy4c08aed2011-07-01 19:47:50 +00004602 register unsigned char
4603 *restrict q;
4604
cristybb503372010-05-27 20:51:26 +00004605 size_t
cristy3ed852e2009-09-05 21:47:34 +00004606 rows;
4607
cristy4c08aed2011-07-01 19:47:50 +00004608 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004609 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004610 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004611 return(MagickTrue);
4612 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4613 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004614 length=(MagickSizeType) nexus_info->region.width*
4615 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004616 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004617 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004618 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004619 switch (cache_info->type)
4620 {
4621 case MemoryCache:
4622 case MapCache:
4623 {
cristy4c08aed2011-07-01 19:47:50 +00004624 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004625 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004626
4627 /*
cristy4c08aed2011-07-01 19:47:50 +00004628 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004629 */
cristydd341db2010-03-04 19:06:38 +00004630 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004631 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004632 {
cristy48078b12010-09-23 17:11:01 +00004633 length=extent;
cristydd341db2010-03-04 19:06:38 +00004634 rows=1UL;
4635 }
cristy4c08aed2011-07-01 19:47:50 +00004636 p=(unsigned char *) cache_info->metacontent+offset*
4637 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004638 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004639 {
cristy8f036fe2010-09-18 02:02:00 +00004640 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004641 p+=cache_info->metacontent_extent*cache_info->columns;
4642 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004643 }
4644 break;
4645 }
4646 case DiskCache:
4647 {
4648 /*
cristy4c08aed2011-07-01 19:47:50 +00004649 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004650 */
4651 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4652 {
4653 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4654 cache_info->cache_filename);
4655 return(MagickFalse);
4656 }
cristydd341db2010-03-04 19:06:38 +00004657 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004658 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004659 {
cristy48078b12010-09-23 17:11:01 +00004660 length=extent;
cristydd341db2010-03-04 19:06:38 +00004661 rows=1UL;
4662 }
cristy48078b12010-09-23 17:11:01 +00004663 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004664 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004665 {
cristy48078b12010-09-23 17:11:01 +00004666 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004667 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004668 cache_info->metacontent_extent,length,(unsigned char *) q);
4669 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004670 break;
4671 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004672 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004673 }
cristybb503372010-05-27 20:51:26 +00004674 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004675 {
4676 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4677 cache_info->cache_filename);
4678 return(MagickFalse);
4679 }
4680 break;
4681 }
4682 default:
4683 break;
4684 }
4685 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004686 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004687 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004688 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004689 nexus_info->region.width,(double) nexus_info->region.height,(double)
4690 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004691 return(MagickTrue);
4692}
4693
4694/*
4695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4696% %
4697% %
4698% %
4699+ R e a d P i x e l C a c h e P i x e l s %
4700% %
4701% %
4702% %
4703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4704%
4705% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4706% cache.
4707%
4708% The format of the ReadPixelCachePixels() method is:
4709%
4710% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4711% NexusInfo *nexus_info,ExceptionInfo *exception)
4712%
4713% A description of each parameter follows:
4714%
4715% o cache_info: the pixel cache.
4716%
4717% o nexus_info: the cache nexus to read the pixels.
4718%
4719% o exception: return any errors or warnings in this structure.
4720%
4721*/
4722static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4723 NexusInfo *nexus_info,ExceptionInfo *exception)
4724{
4725 MagickOffsetType
4726 count,
4727 offset;
4728
4729 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004730 extent,
4731 length;
cristy3ed852e2009-09-05 21:47:34 +00004732
cristy4c08aed2011-07-01 19:47:50 +00004733 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004734 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004735
cristye076a6e2010-08-15 19:59:43 +00004736 register ssize_t
4737 y;
4738
cristybb503372010-05-27 20:51:26 +00004739 size_t
cristy3ed852e2009-09-05 21:47:34 +00004740 rows;
4741
cristy4c08aed2011-07-01 19:47:50 +00004742 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004743 return(MagickTrue);
4744 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4745 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004746 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004747 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004748 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004749 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004750 q=nexus_info->pixels;
4751 switch (cache_info->type)
4752 {
4753 case MemoryCache:
4754 case MapCache:
4755 {
cristy4c08aed2011-07-01 19:47:50 +00004756 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004757 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004758
4759 /*
4760 Read pixels from memory.
4761 */
cristydd341db2010-03-04 19:06:38 +00004762 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004763 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004764 {
cristy48078b12010-09-23 17:11:01 +00004765 length=extent;
cristydd341db2010-03-04 19:06:38 +00004766 rows=1UL;
4767 }
cristyed231572011-07-14 02:18:59 +00004768 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004769 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004770 {
cristy8f036fe2010-09-18 02:02:00 +00004771 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004772 p+=cache_info->number_channels*cache_info->columns;
4773 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004774 }
4775 break;
4776 }
4777 case DiskCache:
4778 {
4779 /*
4780 Read pixels from disk.
4781 */
4782 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4783 {
4784 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4785 cache_info->cache_filename);
4786 return(MagickFalse);
4787 }
cristydd341db2010-03-04 19:06:38 +00004788 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004789 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004790 {
cristy48078b12010-09-23 17:11:01 +00004791 length=extent;
cristydd341db2010-03-04 19:06:38 +00004792 rows=1UL;
4793 }
cristybb503372010-05-27 20:51:26 +00004794 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004795 {
4796 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004797 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004798 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004799 break;
4800 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004801 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004802 }
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;
cristy5e044432011-07-16 03:35:35 +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*/
5121MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5122 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% %
cristy6e437132011-08-12 13:02:19 +00005319% S y n c I m a g e P i x e l C a c h e %
5320% %
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*/
5341MagickExport MagickBooleanType SyncImagePixelCache(Image *image,
5342 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 }
cristybb503372010-05-27 20:51:26 +00005467 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005468 {
5469 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5470 cache_info->cache_filename);
5471 return(MagickFalse);
5472 }
5473 break;
5474 }
5475 default:
5476 break;
5477 }
5478 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005479 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005480 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005481 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005482 nexus_info->region.width,(double) nexus_info->region.height,(double)
5483 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005484 return(MagickTrue);
5485}
5486
5487/*
5488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5489% %
5490% %
5491% %
5492+ W r i t e C a c h e P i x e l s %
5493% %
5494% %
5495% %
5496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5497%
5498% WritePixelCachePixels() writes image pixels to the specified region of the
5499% pixel cache.
5500%
5501% The format of the WritePixelCachePixels() method is:
5502%
5503% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5504% NexusInfo *nexus_info,ExceptionInfo *exception)
5505%
5506% A description of each parameter follows:
5507%
5508% o cache_info: the pixel cache.
5509%
5510% o nexus_info: the cache nexus to write the pixels.
5511%
5512% o exception: return any errors or warnings in this structure.
5513%
5514*/
5515static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5516 NexusInfo *nexus_info,ExceptionInfo *exception)
5517{
5518 MagickOffsetType
5519 count,
5520 offset;
5521
5522 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005523 extent,
5524 length;
cristy3ed852e2009-09-05 21:47:34 +00005525
cristy4c08aed2011-07-01 19:47:50 +00005526 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005527 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005528
cristybb503372010-05-27 20:51:26 +00005529 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005530 y;
5531
cristybb503372010-05-27 20:51:26 +00005532 size_t
cristy3ed852e2009-09-05 21:47:34 +00005533 rows;
5534
cristy4c08aed2011-07-01 19:47:50 +00005535 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005536 return(MagickTrue);
5537 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5538 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005539 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005540 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005541 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005542 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005543 p=nexus_info->pixels;
5544 switch (cache_info->type)
5545 {
5546 case MemoryCache:
5547 case MapCache:
5548 {
cristy4c08aed2011-07-01 19:47:50 +00005549 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005550 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005551
5552 /*
5553 Write pixels to memory.
5554 */
cristydd341db2010-03-04 19:06:38 +00005555 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005556 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005557 {
cristy48078b12010-09-23 17:11:01 +00005558 length=extent;
cristydd341db2010-03-04 19:06:38 +00005559 rows=1UL;
5560 }
cristyed231572011-07-14 02:18:59 +00005561 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005562 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005563 {
cristy8f036fe2010-09-18 02:02:00 +00005564 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005565 p+=nexus_info->region.width*cache_info->number_channels;
5566 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005567 }
5568 break;
5569 }
5570 case DiskCache:
5571 {
5572 /*
5573 Write pixels to disk.
5574 */
5575 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5576 {
5577 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5578 cache_info->cache_filename);
5579 return(MagickFalse);
5580 }
cristydd341db2010-03-04 19:06:38 +00005581 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005582 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005583 {
cristy48078b12010-09-23 17:11:01 +00005584 length=extent;
cristydd341db2010-03-04 19:06:38 +00005585 rows=1UL;
5586 }
cristybb503372010-05-27 20:51:26 +00005587 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005588 {
5589 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005590 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005591 p);
5592 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005593 break;
cristyed231572011-07-14 02:18:59 +00005594 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005595 offset+=cache_info->columns;
5596 }
cristybb503372010-05-27 20:51:26 +00005597 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005598 {
5599 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5600 cache_info->cache_filename);
5601 return(MagickFalse);
5602 }
5603 break;
5604 }
5605 default:
5606 break;
5607 }
5608 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005609 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005610 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005611 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005612 nexus_info->region.width,(double) nexus_info->region.height,(double)
5613 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005614 return(MagickTrue);
5615}