blob: a8dcbdf9ed3238aa98738e0a8772287225747f76 [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% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 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*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#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
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
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
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static 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 *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
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*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
189 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*/
cristy2cd7a752010-08-23 00:48:54 +0000249MagickExport 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
cristy3ed852e2009-09-05 21:47:34 +0000257 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
258 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 {
263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
264 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*/
338MagickExport MagickBooleanType CacheComponentGenesis(void)
339{
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*/
362MagickExport void CacheComponentTerminus(void)
363{
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
386% mask. The method returns MagickTrue if the pixel region is clipped,
387% otherwise MagickFalse.
388%
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
416 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000417 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000418
419 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000420 *restrict nexus_indexes,
421 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000422
cristy3ed852e2009-09-05 21:47:34 +0000423 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000424 *restrict p,
425 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000426
cristye076a6e2010-08-15 19:59:43 +0000427 register ssize_t
428 i;
429
cristy3ed852e2009-09-05 21:47:34 +0000430 /*
431 Apply clip mask.
432 */
433 if (image->debug != MagickFalse)
434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
435 if (image->clip_mask == (Image *) NULL)
436 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000437 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000438 if (cache_info == (Cache) NULL)
439 return(MagickFalse);
440 image_nexus=AcquirePixelCacheNexus(1);
441 clip_nexus=AcquirePixelCacheNexus(1);
442 if ((image_nexus == (NexusInfo **) NULL) ||
443 (clip_nexus == (NexusInfo **) NULL))
444 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
445 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
446 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
447 exception);
cristy2036f5c2010-09-19 21:18:17 +0000448 indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +0000449 q=nexus_info->pixels;
450 nexus_indexes=nexus_info->indexes;
451 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
452 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
453 nexus_info->region.height,clip_nexus[0],exception);
454 number_pixels=(MagickSizeType) nexus_info->region.width*
455 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000456 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000457 {
458 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
459 break;
460 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
461 {
cristyce70c172010-01-07 17:15:30 +0000462 SetRedPixelComponent(q,GetRedPixelComponent(p));
463 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
464 SetBluePixelComponent(q,GetBluePixelComponent(p));
465 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000466 if (cache_info->active_index_channel != MagickFalse)
467 nexus_indexes[i]=indexes[i];
468 }
469 p++;
470 q++;
471 r++;
472 }
473 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
474 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000475 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000476 return(MagickFalse);
477 return(MagickTrue);
478}
479
480/*
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482% %
483% %
484% %
485+ C l o n e P i x e l C a c h e %
486% %
487% %
488% %
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490%
491% ClonePixelCache() clones a pixel cache.
492%
493% The format of the ClonePixelCache() method is:
494%
495% Cache ClonePixelCache(const Cache cache)
496%
497% A description of each parameter follows:
498%
499% o cache: the pixel cache.
500%
501*/
502MagickExport Cache ClonePixelCache(const Cache cache)
503{
504 CacheInfo
505 *clone_info;
506
507 const CacheInfo
508 *cache_info;
509
510 assert(cache != (const Cache) NULL);
511 cache_info=(const CacheInfo *) cache;
512 assert(cache_info->signature == MagickSignature);
513 if (cache_info->debug != MagickFalse)
514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
515 cache_info->filename);
516 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
517 if (clone_info == (Cache) NULL)
518 return((Cache) NULL);
519 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
520 return((Cache ) clone_info);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525% %
526% %
527% %
cristy60c44a82009-10-07 00:58:49 +0000528+ 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 +0000529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
533% ClonePixelCachePixels() clones the source pixel cache to the destination
534% cache.
535%
536% The format of the ClonePixelCachePixels() method is:
537%
538% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
539% CacheInfo *source_info,ExceptionInfo *exception)
540%
541% A description of each parameter follows:
542%
543% o cache_info: the pixel cache.
544%
545% o source_info: the source pixel cache.
546%
547% o exception: return any errors or warnings in this structure.
548%
549*/
550
551static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552{
553 int
554 status;
555
cristy5ee247a2010-02-12 15:42:34 +0000556 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000557 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000558 if (cache_info->file != -1)
559 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000560 cache_info->file=(-1);
561 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563 return(status == -1 ? MagickFalse : MagickTrue);
564}
565
566static void LimitPixelCacheDescriptors(void)
567{
568 register CacheInfo
569 *p,
570 *q;
571
572 /*
573 Limit # of open file descriptors.
574 */
575 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
576 return;
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 if (cache_resources == (SplayTreeInfo *) NULL)
579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return;
582 }
583 ResetSplayTreeIterator(cache_resources);
584 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585 while (p != (CacheInfo *) NULL)
586 {
587 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000588 break;
cristy3ed852e2009-09-05 21:47:34 +0000589 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
590 }
591 for (q=p; p != (CacheInfo *) NULL; )
592 {
593 if ((p->type == DiskCache) && (p->file != -1) &&
594 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000595 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000596 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
597 }
598 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000599 {
600 /*
601 Close least recently used cache.
602 */
603 (void) close(q->file);
604 q->file=(-1);
605 }
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607}
608
609static inline MagickSizeType MagickMax(const MagickSizeType x,
610 const MagickSizeType y)
611{
612 if (x > y)
613 return(x);
614 return(y);
615}
616
617static inline MagickSizeType MagickMin(const MagickSizeType x,
618 const MagickSizeType y)
619{
620 if (x < y)
621 return(x);
622 return(y);
623}
624
625static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
626 const MapMode mode)
627{
628 int
629 file;
630
631 /*
632 Open pixel cache on disk.
633 */
cristyf84a1932010-01-03 18:00:18 +0000634 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 if (cache_info->file != -1)
636 {
cristyf84a1932010-01-03 18:00:18 +0000637 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000638 return(MagickTrue); /* cache already open */
639 }
640 LimitPixelCacheDescriptors();
641 if (*cache_info->cache_filename == '\0')
642 file=AcquireUniqueFileResource(cache_info->cache_filename);
643 else
644 switch (mode)
645 {
646 case ReadMode:
647 {
648 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
649 break;
650 }
651 case WriteMode:
652 {
653 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
654 O_EXCL,S_MODE);
655 if (file == -1)
656 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
657 break;
658 }
659 case IOMode:
660 default:
661 {
662 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
663 O_EXCL,S_MODE);
664 if (file == -1)
665 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
666 break;
667 }
668 }
669 if (file == -1)
670 {
cristyf84a1932010-01-03 18:00:18 +0000671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000672 return(MagickFalse);
673 }
674 (void) AcquireMagickResource(FileResource,1);
675 cache_info->file=file;
676 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
681static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000683 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000684{
685 register MagickOffsetType
686 i;
687
688 ssize_t
689 count;
690
cristy08a88202010-03-04 19:18:05 +0000691 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000692#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000693 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
695 {
cristyf84a1932010-01-03 18:00:18 +0000696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000697 return((MagickOffsetType) -1);
698 }
699#endif
700 count=0;
701 for (i=0; i < (MagickOffsetType) length; i+=count)
702 {
703#if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
706#else
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
709#endif
710 if (count > 0)
711 continue;
712 count=0;
713 if (errno != EINTR)
714 {
715 i=(-1);
716 break;
717 }
718 }
719#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000721#endif
722 return(i);
723}
724
725static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000727 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000728{
729 register MagickOffsetType
730 i;
731
732 ssize_t
733 count;
734
cristy08a88202010-03-04 19:18:05 +0000735 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000736#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return((MagickOffsetType) -1);
742 }
743#endif
744 count=0;
745 for (i=0; i < (MagickOffsetType) length; i+=count)
746 {
747#if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
750#else
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
753#endif
754 if (count > 0)
755 continue;
756 count=0;
757 if (errno != EINTR)
758 {
759 i=(-1);
760 break;
761 }
762 }
763#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000765#endif
766 return(i);
767}
768
769static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
771{
772 MagickOffsetType
773 count,
774 offset,
775 source_offset;
776
777 MagickSizeType
778 length;
779
cristy3ed852e2009-09-05 21:47:34 +0000780 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000781 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000782
cristye076a6e2010-08-15 19:59:43 +0000783 register ssize_t
784 y;
785
cristybb503372010-05-27 20:51:26 +0000786 size_t
cristy3ed852e2009-09-05 21:47:34 +0000787 columns,
788 rows;
789
790 if (cache_info->debug != MagickFalse)
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
793 {
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 clone_info->cache_filename);
796 return(MagickFalse);
797 }
798 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
799 {
800 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801 cache_info->cache_filename);
802 return(MagickFalse);
803 }
cristybb503372010-05-27 20:51:26 +0000804 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000806 if ((clone_info->active_index_channel != MagickFalse) &&
807 (cache_info->active_index_channel != MagickFalse))
808 {
809 register IndexPacket
810 *indexes;
811
812 /*
813 Clone cache indexes.
814 */
815 length=MagickMax(clone_info->columns,cache_info->columns)*
816 sizeof(*indexes);
817 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818 if (indexes == (IndexPacket *) NULL)
819 {
820 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
822 return(MagickFalse);
823 }
824 (void) ResetMagickMemory(indexes,0,(size_t) length);
825 length=columns*sizeof(*indexes);
826 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000830 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000831 {
832 source_offset-=cache_info->columns*sizeof(*indexes);
833 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834 length,(unsigned char *) indexes);
835 if ((MagickSizeType) count != length)
836 break;
837 offset-=clone_info->columns*sizeof(*indexes);
838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
841 break;
842 }
cristybb503372010-05-27 20:51:26 +0000843 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000844 {
845 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846 ThrowFileException(exception,CacheError,"UnableToCloneCache",
847 cache_info->cache_filename);
848 return(MagickFalse);
849 }
850 if (clone_info->columns > cache_info->columns)
851 {
852 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853 (void) ResetMagickMemory(indexes,0,(size_t) length);
854 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000856 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
858 offset-=clone_info->columns*sizeof(*indexes);
859 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860 length,(unsigned char *) indexes);
861 if ((MagickSizeType) count != length)
862 break;
863 }
cristybb503372010-05-27 20:51:26 +0000864 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 ThrowFileException(exception,CacheError,"UnableToCloneCache",
868 cache_info->cache_filename);
869 return(MagickFalse);
870 }
871 }
872 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
873 }
874 /*
875 Clone cache pixels.
876 */
877 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879 if (pixels == (PixelPacket *) NULL)
880 {
881 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
883 return(MagickFalse);
884 }
885 (void) ResetMagickMemory(pixels,0,(size_t) length);
886 length=columns*sizeof(*pixels);
887 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000889 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000890 {
891 source_offset-=cache_info->columns*sizeof(*pixels);
892 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893 length,(unsigned char *) pixels);
894 if ((MagickSizeType) count != length)
895 break;
896 offset-=clone_info->columns*sizeof(*pixels);
897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
900 break;
901 }
cristybb503372010-05-27 20:51:26 +0000902 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000903 {
904 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905 ThrowFileException(exception,CacheError,"UnableToCloneCache",
906 cache_info->cache_filename);
907 return(MagickFalse);
908 }
909 if (clone_info->columns > cache_info->columns)
910 {
911 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
912 sizeof(*pixels);
913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000915 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000916 {
917 offset-=clone_info->columns*sizeof(*pixels);
918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
921 break;
922 }
cristybb503372010-05-27 20:51:26 +0000923 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000924 {
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 ThrowFileException(exception,CacheError,"UnableToCloneCache",
927 cache_info->cache_filename);
928 return(MagickFalse);
929 }
930 }
931 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
932 return(MagickTrue);
933}
934
935static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936 CacheInfo *cache_info,ExceptionInfo *exception)
937{
938 MagickOffsetType
939 count,
940 offset;
941
942 MagickSizeType
943 length;
944
cristy3ed852e2009-09-05 21:47:34 +0000945 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000946 *restrict pixels,
947 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000948
cristye076a6e2010-08-15 19:59:43 +0000949 register ssize_t
950 y;
951
cristybb503372010-05-27 20:51:26 +0000952 size_t
cristy3ed852e2009-09-05 21:47:34 +0000953 columns,
954 rows;
955
956 if (cache_info->debug != MagickFalse)
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
959 {
960 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961 cache_info->cache_filename);
962 return(MagickFalse);
963 }
cristybb503372010-05-27 20:51:26 +0000964 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000966 if ((clone_info->active_index_channel != MagickFalse) &&
967 (cache_info->active_index_channel != MagickFalse))
968 {
969 register IndexPacket
970 *indexes,
971 *q;
972
973 /*
974 Clone cache indexes.
975 */
976 length=MagickMax(clone_info->columns,cache_info->columns)*
977 sizeof(*indexes);
978 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979 if (indexes == (IndexPacket *) NULL)
980 {
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983 return(MagickFalse);
984 }
985 (void) ResetMagickMemory(indexes,0,(size_t) length);
986 length=columns*sizeof(IndexPacket);
987 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 offset-=cache_info->columns*sizeof(IndexPacket);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
996 break;
997 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +0000998 (void) memcpy(q,indexes,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000999 if ((MagickSizeType) count != length)
1000 break;
1001 }
cristybb503372010-05-27 20:51:26 +00001002 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1008 }
1009 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1010 }
1011 /*
1012 Clone cache pixels.
1013 */
1014 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016 if (pixels == (PixelPacket *) NULL)
1017 {
1018 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020 return(MagickFalse);
1021 }
1022 (void) ResetMagickMemory(pixels,0,(size_t) length);
1023 length=columns*sizeof(*pixels);
1024 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001026 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
1028 offset-=cache_info->columns*sizeof(*pixels);
1029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1032 break;
1033 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001034 (void) memcpy(q,pixels,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001035 }
cristybb503372010-05-27 20:51:26 +00001036 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001037 {
1038 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040 cache_info->cache_filename);
1041 return(MagickFalse);
1042 }
1043 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1044 return(MagickTrue);
1045}
1046
1047static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1049{
1050 MagickOffsetType
1051 count,
1052 offset;
1053
1054 MagickSizeType
1055 length;
1056
cristy3ed852e2009-09-05 21:47:34 +00001057 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001058 *restrict p,
1059 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001060
cristye076a6e2010-08-15 19:59:43 +00001061 register ssize_t
1062 y;
1063
cristybb503372010-05-27 20:51:26 +00001064 size_t
cristy3ed852e2009-09-05 21:47:34 +00001065 columns,
1066 rows;
1067
1068 if (cache_info->debug != MagickFalse)
1069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1071 {
1072 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073 clone_info->cache_filename);
1074 return(MagickFalse);
1075 }
cristybb503372010-05-27 20:51:26 +00001076 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001078 if ((clone_info->active_index_channel != MagickFalse) &&
1079 (cache_info->active_index_channel != MagickFalse))
1080 {
1081 register IndexPacket
1082 *p,
1083 *indexes;
1084
1085 /*
1086 Clone cache indexes.
1087 */
1088 length=MagickMax(clone_info->columns,cache_info->columns)*
1089 sizeof(*indexes);
1090 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091 if (indexes == (IndexPacket *) NULL)
1092 {
1093 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095 return(MagickFalse);
1096 }
1097 (void) ResetMagickMemory(indexes,0,(size_t) length);
1098 length=columns*sizeof(*indexes);
1099 p=cache_info->indexes+cache_info->columns*rows;
1100 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001102 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
1104 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001105 (void) memcpy(indexes,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001106 offset-=clone_info->columns*sizeof(*indexes);
1107 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108 (unsigned char *) indexes);
1109 if ((MagickSizeType) count != length)
1110 break;
1111 }
cristybb503372010-05-27 20:51:26 +00001112 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001113 {
1114 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116 cache_info->cache_filename);
1117 return(MagickFalse);
1118 }
1119 if (clone_info->columns > cache_info->columns)
1120 {
1121 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122 (void) ResetMagickMemory(indexes,0,(size_t) length);
1123 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001125 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001126 {
1127 offset-=clone_info->columns*sizeof(*indexes);
1128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1131 break;
1132 }
cristybb503372010-05-27 20:51:26 +00001133 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001134 {
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137 cache_info->cache_filename);
1138 return(MagickFalse);
1139 }
1140 }
1141 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1142 }
1143 /*
1144 Clone cache pixels.
1145 */
1146 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148 if (pixels == (PixelPacket *) NULL)
1149 {
1150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152 return(MagickFalse);
1153 }
1154 (void) ResetMagickMemory(pixels,0,(size_t) length);
1155 length=columns*sizeof(*pixels);
1156 p=cache_info->pixels+cache_info->columns*rows;
1157 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001158 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001159 {
1160 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001161 (void) memcpy(pixels,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001162 offset-=clone_info->columns*sizeof(*pixels);
1163 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164 (unsigned char *) pixels);
1165 if ((MagickSizeType) count != length)
1166 break;
1167 }
cristybb503372010-05-27 20:51:26 +00001168 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001169 {
1170 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172 cache_info->cache_filename);
1173 return(MagickFalse);
1174 }
1175 if (clone_info->columns > cache_info->columns)
1176 {
1177 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1178 sizeof(*pixels);
1179 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001181 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001182 {
1183 offset-=clone_info->columns*sizeof(*pixels);
1184 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185 (unsigned char *) pixels);
1186 if ((MagickSizeType) count != length)
1187 break;
1188 }
cristybb503372010-05-27 20:51:26 +00001189 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001190 {
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193 cache_info->cache_filename);
1194 return(MagickFalse);
1195 }
1196 }
1197 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1198 return(MagickTrue);
1199}
1200
1201static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1203{
cristy3ed852e2009-09-05 21:47:34 +00001204 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001205 *restrict pixels,
1206 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001207
cristye076a6e2010-08-15 19:59:43 +00001208 register ssize_t
1209 y;
cristy3ed852e2009-09-05 21:47:34 +00001210
cristybb503372010-05-27 20:51:26 +00001211 size_t
cristy3ed852e2009-09-05 21:47:34 +00001212 columns,
cristye076a6e2010-08-15 19:59:43 +00001213 length,
cristy3ed852e2009-09-05 21:47:34 +00001214 rows;
1215
1216 if (cache_info->debug != MagickFalse)
1217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001218 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001220 if ((clone_info->active_index_channel != MagickFalse) &&
1221 (cache_info->active_index_channel != MagickFalse))
1222 {
1223 register IndexPacket
1224 *indexes,
1225 *source_indexes;
1226
1227 /*
1228 Clone cache indexes.
1229 */
1230 length=columns*sizeof(*indexes);
1231 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001232 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001233 else
1234 {
1235 source_indexes=cache_info->indexes+cache_info->columns*rows;
1236 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001237 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001238 {
1239 source_indexes-=cache_info->columns;
1240 indexes-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001241 (void) memcpy(indexes,source_indexes,length);
cristy3ed852e2009-09-05 21:47:34 +00001242 }
1243 if (clone_info->columns > cache_info->columns)
1244 {
1245 length=(clone_info->columns-cache_info->columns)*
1246 sizeof(*indexes);
1247 indexes=clone_info->indexes+clone_info->columns*rows+
1248 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001249 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001250 {
1251 indexes-=clone_info->columns;
1252 (void) ResetMagickMemory(indexes,0,length);
1253 }
1254 }
1255 }
1256 }
1257 /*
1258 Clone cache pixels.
1259 */
1260 length=columns*sizeof(*pixels);
1261 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001262 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001263 else
1264 {
1265 source_pixels=cache_info->pixels+cache_info->columns*rows;
1266 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001267 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001268 {
1269 source_pixels-=cache_info->columns;
1270 pixels-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001271 (void) memcpy(pixels,source_pixels,length);
cristy3ed852e2009-09-05 21:47:34 +00001272 }
1273 if (clone_info->columns > cache_info->columns)
1274 {
1275 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276 pixels=clone_info->pixels+clone_info->columns*rows+
1277 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001278 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001279 {
1280 pixels-=clone_info->columns;
1281 (void) ResetMagickMemory(pixels,0,length);
1282 }
1283 }
1284 }
1285 return(MagickTrue);
1286}
1287
1288static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1289 CacheInfo *cache_info,ExceptionInfo *exception)
1290{
1291 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1292 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1293 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1294 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1295 if (cache_info->type == DiskCache)
1296 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1297 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1298}
1299
1300/*
1301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302% %
1303% %
1304% %
1305+ C l o n e P i x e l C a c h e M e t h o d s %
1306% %
1307% %
1308% %
1309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310%
1311% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1312% another.
1313%
1314% The format of the ClonePixelCacheMethods() method is:
1315%
1316% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1317%
1318% A description of each parameter follows:
1319%
1320% o clone: Specifies a pointer to a Cache structure.
1321%
1322% o cache: the pixel cache.
1323%
1324*/
1325MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1326{
1327 CacheInfo
1328 *cache_info,
1329 *source_info;
1330
1331 assert(clone != (Cache) NULL);
1332 source_info=(CacheInfo *) clone;
1333 assert(source_info->signature == MagickSignature);
1334 if (source_info->debug != MagickFalse)
1335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1336 source_info->filename);
1337 assert(cache != (Cache) NULL);
1338 cache_info=(CacheInfo *) cache;
1339 assert(cache_info->signature == MagickSignature);
1340 source_info->methods=cache_info->methods;
1341}
1342
1343/*
1344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345% %
1346% %
1347% %
1348+ D e s t r o y I m a g e P i x e l C a c h e %
1349% %
1350% %
1351% %
1352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353%
1354% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1355%
1356% The format of the DestroyImagePixelCache() method is:
1357%
1358% void DestroyImagePixelCache(Image *image)
1359%
1360% A description of each parameter follows:
1361%
1362% o image: the image.
1363%
1364*/
1365static void DestroyImagePixelCache(Image *image)
1366{
1367 assert(image != (Image *) NULL);
1368 assert(image->signature == MagickSignature);
1369 if (image->debug != MagickFalse)
1370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1371 if (image->cache == (void *) NULL)
1372 return;
1373 image->cache=DestroyPixelCache(image->cache);
1374}
1375
1376/*
1377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378% %
1379% %
1380% %
1381+ D e s t r o y I m a g e P i x e l s %
1382% %
1383% %
1384% %
1385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386%
1387% DestroyImagePixels() deallocates memory associated with the pixel cache.
1388%
1389% The format of the DestroyImagePixels() method is:
1390%
1391% void DestroyImagePixels(Image *image)
1392%
1393% A description of each parameter follows:
1394%
1395% o image: the image.
1396%
1397*/
1398MagickExport void DestroyImagePixels(Image *image)
1399{
1400 CacheInfo
1401 *cache_info;
1402
1403 assert(image != (const Image *) NULL);
1404 assert(image->signature == MagickSignature);
1405 if (image->debug != MagickFalse)
1406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1407 assert(image->cache != (Cache) NULL);
1408 cache_info=(CacheInfo *) image->cache;
1409 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001410 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1411 {
1412 cache_info->methods.destroy_pixel_handler(image);
1413 return;
1414 }
cristy2036f5c2010-09-19 21:18:17 +00001415 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001416}
1417
1418/*
1419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420% %
1421% %
1422% %
1423+ D e s t r o y P i x e l C a c h e %
1424% %
1425% %
1426% %
1427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428%
1429% DestroyPixelCache() deallocates memory associated with the pixel cache.
1430%
1431% The format of the DestroyPixelCache() method is:
1432%
1433% Cache DestroyPixelCache(Cache cache)
1434%
1435% A description of each parameter follows:
1436%
1437% o cache: the pixel cache.
1438%
1439*/
1440
1441static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1442{
1443 switch (cache_info->type)
1444 {
1445 case MemoryCache:
1446 {
1447 if (cache_info->mapped == MagickFalse)
1448 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1449 cache_info->pixels);
1450 else
1451 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1452 (size_t) cache_info->length);
1453 RelinquishMagickResource(MemoryResource,cache_info->length);
1454 break;
1455 }
1456 case MapCache:
1457 {
1458 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1459 cache_info->length);
1460 RelinquishMagickResource(MapResource,cache_info->length);
1461 }
1462 case DiskCache:
1463 {
1464 if (cache_info->file != -1)
1465 (void) ClosePixelCacheOnDisk(cache_info);
1466 RelinquishMagickResource(DiskResource,cache_info->length);
1467 break;
1468 }
1469 default:
1470 break;
1471 }
1472 cache_info->type=UndefinedCache;
1473 cache_info->mapped=MagickFalse;
1474 cache_info->indexes=(IndexPacket *) NULL;
1475}
1476
1477MagickExport Cache DestroyPixelCache(Cache cache)
1478{
1479 CacheInfo
1480 *cache_info;
1481
cristy3ed852e2009-09-05 21:47:34 +00001482 assert(cache != (Cache) NULL);
1483 cache_info=(CacheInfo *) cache;
1484 assert(cache_info->signature == MagickSignature);
1485 if (cache_info->debug != MagickFalse)
1486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1487 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001488 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001489 cache_info->reference_count--;
1490 if (cache_info->reference_count != 0)
1491 {
cristyf84a1932010-01-03 18:00:18 +00001492 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001493 return((Cache) NULL);
1494 }
cristyf84a1932010-01-03 18:00:18 +00001495 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001496 if (cache_resources != (SplayTreeInfo *) NULL)
1497 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001498 if (cache_info->debug != MagickFalse)
1499 {
1500 char
1501 message[MaxTextExtent];
1502
1503 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1504 cache_info->filename);
1505 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1506 }
cristyc2e1bdd2009-09-10 23:43:34 +00001507 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1508 (cache_info->type != DiskCache)))
1509 RelinquishPixelCachePixels(cache_info);
1510 else
1511 {
1512 RelinquishPixelCachePixels(cache_info);
1513 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1514 }
cristy3ed852e2009-09-05 21:47:34 +00001515 *cache_info->cache_filename='\0';
1516 if (cache_info->nexus_info != (NexusInfo **) NULL)
1517 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1518 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001519 if (cache_info->random_info != (RandomInfo *) NULL)
1520 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001521 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1522 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1523 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1524 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001525 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001526 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1527 cache=(Cache) NULL;
1528 return(cache);
1529}
1530
1531/*
1532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533% %
1534% %
1535% %
1536+ D e s t r o y P i x e l C a c h e N e x u s %
1537% %
1538% %
1539% %
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541%
1542% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1543%
1544% The format of the DestroyPixelCacheNexus() method is:
1545%
1546% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001547% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001548%
1549% A description of each parameter follows:
1550%
1551% o nexus_info: the nexus to destroy.
1552%
1553% o number_threads: the number of nexus threads.
1554%
1555*/
1556
1557static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1558{
1559 if (nexus_info->mapped == MagickFalse)
1560 (void) RelinquishMagickMemory(nexus_info->cache);
1561 else
1562 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1563 nexus_info->cache=(PixelPacket *) NULL;
1564 nexus_info->pixels=(PixelPacket *) NULL;
1565 nexus_info->indexes=(IndexPacket *) NULL;
1566 nexus_info->length=0;
1567 nexus_info->mapped=MagickFalse;
1568}
1569
1570MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001571 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001572{
cristybb503372010-05-27 20:51:26 +00001573 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001574 i;
1575
1576 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001577 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001578 {
1579 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1580 RelinquishCacheNexusPixels(nexus_info[i]);
1581 nexus_info[i]->signature=(~MagickSignature);
1582 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1583 }
1584 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1585 return(nexus_info);
1586}
1587
1588/*
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590% %
1591% %
1592% %
cristy3ed852e2009-09-05 21:47:34 +00001593+ G e t A u t h e n t i c I n d e x e s F r o m C a c h e %
1594% %
1595% %
1596% %
1597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598%
1599% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1600% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1601%
1602% The format of the GetAuthenticIndexesFromCache() method is:
1603%
1604% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1605%
1606% A description of each parameter follows:
1607%
1608% o image: the image.
1609%
1610*/
1611static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1612{
1613 CacheInfo
1614 *cache_info;
1615
cristy5c9e6f22010-09-17 17:31:01 +00001616 const int
1617 id = GetOpenMPThreadId();
1618
cristye7cc7cf2010-09-21 13:26:47 +00001619 assert(image != (const Image *) NULL);
1620 assert(image->signature == MagickSignature);
1621 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001622 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001623 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001624 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001625 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001626}
1627
1628/*
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630% %
1631% %
1632% %
1633% G e t A u t h e n t i c I n d e x Q u e u e %
1634% %
1635% %
1636% %
1637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638%
1639% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1640% indexes associated with the last call to QueueAuthenticPixels() or
1641% GetVirtualPixels(). NULL is returned if the black channel or colormap
1642% indexes are not available.
1643%
1644% The format of the GetAuthenticIndexQueue() method is:
1645%
1646% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1647%
1648% A description of each parameter follows:
1649%
1650% o image: the image.
1651%
1652*/
1653MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1654{
1655 CacheInfo
1656 *cache_info;
1657
cristy2036f5c2010-09-19 21:18:17 +00001658 const int
1659 id = GetOpenMPThreadId();
1660
cristy3ed852e2009-09-05 21:47:34 +00001661 assert(image != (const Image *) NULL);
1662 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001663 assert(image->cache != (Cache) NULL);
1664 cache_info=(CacheInfo *) image->cache;
1665 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001666 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001667 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001668 return(cache_info->methods.get_authentic_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001669 assert(id < (int) cache_info->number_threads);
1670 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
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 C a c h e N e x u s %
1679% %
1680% %
1681% %
1682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683%
1684% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1685% disk pixel cache as defined by the geometry parameters. A pointer to the
1686% pixels is returned if the pixels are transferred, otherwise a NULL is
1687% returned.
1688%
1689% The format of the GetAuthenticPixelCacheNexus() method is:
1690%
cristybb503372010-05-27 20:51:26 +00001691% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1692% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001693% NexusInfo *nexus_info,ExceptionInfo *exception)
1694%
1695% A description of each parameter follows:
1696%
1697% o image: the image.
1698%
1699% o x,y,columns,rows: These values define the perimeter of a region of
1700% pixels.
1701%
1702% o nexus_info: the cache nexus to return.
1703%
1704% o exception: return any errors or warnings in this structure.
1705%
1706*/
1707
1708static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1709 NexusInfo *nexus_info)
1710{
1711 MagickOffsetType
1712 offset;
1713
cristy73724512010-04-12 14:43:14 +00001714 if (cache_info->type == PingCache)
1715 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001716 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1717 nexus_info->region.x;
1718 if (nexus_info->pixels != (cache_info->pixels+offset))
1719 return(MagickFalse);
1720 return(MagickTrue);
1721}
1722
cristye076a6e2010-08-15 19:59:43 +00001723MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1724 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001725 NexusInfo *nexus_info,ExceptionInfo *exception)
1726{
1727 CacheInfo
1728 *cache_info;
1729
1730 PixelPacket
1731 *pixels;
1732
1733 /*
1734 Transfer pixels from the cache.
1735 */
1736 assert(image != (Image *) NULL);
1737 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001738 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1739 if (pixels == (PixelPacket *) NULL)
1740 return((PixelPacket *) NULL);
1741 cache_info=(CacheInfo *) image->cache;
1742 assert(cache_info->signature == MagickSignature);
1743 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1744 return(pixels);
1745 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1746 return((PixelPacket *) NULL);
1747 if (cache_info->active_index_channel != MagickFalse)
1748 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1749 return((PixelPacket *) NULL);
1750 return(pixels);
1751}
1752
1753/*
1754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1755% %
1756% %
1757% %
1758+ 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 %
1759% %
1760% %
1761% %
1762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763%
1764% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1765% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1766%
1767% The format of the GetAuthenticPixelsFromCache() method is:
1768%
1769% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1770%
1771% A description of each parameter follows:
1772%
1773% o image: the image.
1774%
1775*/
1776static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1777{
1778 CacheInfo
1779 *cache_info;
1780
cristy5c9e6f22010-09-17 17:31:01 +00001781 const int
1782 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001783
cristye7cc7cf2010-09-21 13:26:47 +00001784 assert(image != (const Image *) NULL);
1785 assert(image->signature == MagickSignature);
1786 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001787 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001788 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001789 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001790 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001791}
1792
1793/*
1794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1795% %
1796% %
1797% %
1798% G e t A u t h e n t i c P i x e l Q u e u e %
1799% %
1800% %
1801% %
1802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1803%
1804% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1805% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1806%
1807% The format of the GetAuthenticPixelQueue() method is:
1808%
1809% PixelPacket *GetAuthenticPixelQueue(const Image image)
1810%
1811% A description of each parameter follows:
1812%
1813% o image: the image.
1814%
1815*/
1816MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1817{
1818 CacheInfo
1819 *cache_info;
1820
cristy2036f5c2010-09-19 21:18:17 +00001821 const int
1822 id = GetOpenMPThreadId();
1823
cristy3ed852e2009-09-05 21:47:34 +00001824 assert(image != (const Image *) NULL);
1825 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001826 assert(image->cache != (Cache) NULL);
1827 cache_info=(CacheInfo *) image->cache;
1828 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001829 if (cache_info->methods.get_authentic_pixels_from_handler !=
1830 (GetAuthenticPixelsFromHandler) NULL)
1831 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001832 assert(id < (int) cache_info->number_threads);
1833 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001834}
1835
1836/*
1837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1838% %
1839% %
1840% %
1841% G e t A u t h e n t i c P i x e l s %
1842% %
1843% %
1844% %
1845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1846%
1847% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1848% region is successfully accessed, a pointer to a PixelPacket array
1849% representing the region is returned, otherwise NULL is returned.
1850%
1851% The returned pointer may point to a temporary working copy of the pixels
1852% or it may point to the original pixels in memory. Performance is maximized
1853% if the selected region is part of one row, or one or more full rows, since
1854% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001855% if the image is in memory, or in a memory-mapped file. The returned pointer
1856% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001857%
1858% Pixels accessed via the returned pointer represent a simple array of type
1859% PixelPacket. If the image type is CMYK or if the storage class is
1860% PseduoClass, call GetAuthenticIndexQueue() after invoking
1861% GetAuthenticPixels() to obtain the black color component or colormap indexes
1862% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1863% (and/or IndexPacket) array has been updated, the changes must be saved back
1864% to the underlying image using SyncAuthenticPixels() or they may be lost.
1865%
1866% The format of the GetAuthenticPixels() method is:
1867%
cristy5f959472010-05-27 22:19:46 +00001868% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1869% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001870% ExceptionInfo *exception)
1871%
1872% A description of each parameter follows:
1873%
1874% o image: the image.
1875%
1876% o x,y,columns,rows: These values define the perimeter of a region of
1877% pixels.
1878%
1879% o exception: return any errors or warnings in this structure.
1880%
1881*/
cristybb503372010-05-27 20:51:26 +00001882MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1883 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001884 ExceptionInfo *exception)
1885{
1886 CacheInfo
1887 *cache_info;
1888
cristy2036f5c2010-09-19 21:18:17 +00001889 const int
1890 id = GetOpenMPThreadId();
1891
cristy3ed852e2009-09-05 21:47:34 +00001892 assert(image != (Image *) NULL);
1893 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001894 assert(image->cache != (Cache) NULL);
1895 cache_info=(CacheInfo *) image->cache;
1896 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001897 if (cache_info->methods.get_authentic_pixels_handler !=
1898 (GetAuthenticPixelsHandler) NULL)
1899 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1900 rows,exception));
cristye7cc7cf2010-09-21 13:26:47 +00001901 return(GetAuthenticPixelsCache(image,x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00001902 assert(id < (int) cache_info->number_threads);
1903 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1904 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001905}
1906
1907/*
1908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1909% %
1910% %
1911% %
1912+ G e t A u t h e n t i c P i x e l s C a c h e %
1913% %
1914% %
1915% %
1916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1917%
1918% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1919% as defined by the geometry parameters. A pointer to the pixels is returned
1920% if the pixels are transferred, otherwise a NULL is returned.
1921%
1922% The format of the GetAuthenticPixelsCache() method is:
1923%
cristybb503372010-05-27 20:51:26 +00001924% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1925% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001926% ExceptionInfo *exception)
1927%
1928% A description of each parameter follows:
1929%
1930% o image: the image.
1931%
1932% o x,y,columns,rows: These values define the perimeter of a region of
1933% pixels.
1934%
1935% o exception: return any errors or warnings in this structure.
1936%
1937*/
cristybb503372010-05-27 20:51:26 +00001938static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1939 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001940 ExceptionInfo *exception)
1941{
1942 CacheInfo
1943 *cache_info;
1944
cristy5c9e6f22010-09-17 17:31:01 +00001945 const int
1946 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001947
cristye7cc7cf2010-09-21 13:26:47 +00001948 assert(image != (const Image *) NULL);
1949 assert(image->signature == MagickSignature);
1950 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001951 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001952 if (cache_info == (Cache) NULL)
1953 return((PixelPacket *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001954 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001955 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001956 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1957 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001958}
1959
1960/*
1961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1962% %
1963% %
1964% %
1965+ G e t I m a g e E x t e n t %
1966% %
1967% %
1968% %
1969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1970%
1971% GetImageExtent() returns the extent of the pixels associated with the
1972% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1973%
1974% The format of the GetImageExtent() method is:
1975%
1976% MagickSizeType GetImageExtent(const Image *image)
1977%
1978% A description of each parameter follows:
1979%
1980% o image: the image.
1981%
1982*/
1983MagickExport MagickSizeType GetImageExtent(const Image *image)
1984{
1985 CacheInfo
1986 *cache_info;
1987
cristy5c9e6f22010-09-17 17:31:01 +00001988 const int
1989 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001990
cristy3ed852e2009-09-05 21:47:34 +00001991 assert(image != (Image *) NULL);
1992 assert(image->signature == MagickSignature);
1993 if (image->debug != MagickFalse)
1994 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1995 assert(image->cache != (Cache) NULL);
1996 cache_info=(CacheInfo *) image->cache;
1997 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001998 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001999 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002000}
2001
2002/*
2003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2004% %
2005% %
2006% %
2007+ G e t I m a g e P i x e l C a c h e %
2008% %
2009% %
2010% %
2011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2012%
2013% GetImagePixelCache() ensures that there is only a single reference to the
2014% pixel cache to be modified, updating the provided cache pointer to point to
2015% a clone of the original pixel cache if necessary.
2016%
2017% The format of the GetImagePixelCache method is:
2018%
2019% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2020% ExceptionInfo *exception)
2021%
2022% A description of each parameter follows:
2023%
2024% o image: the image.
2025%
2026% o clone: any value other than MagickFalse clones the cache pixels.
2027%
2028% o exception: return any errors or warnings in this structure.
2029%
2030*/
cristy3ed852e2009-09-05 21:47:34 +00002031static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2032{
2033 CacheInfo
2034 *cache_info;
2035
2036 /*
2037 Does the image match the pixel cache morphology?
2038 */
2039 cache_info=(CacheInfo *) image->cache;
2040 if ((image->storage_class != cache_info->storage_class) ||
2041 (image->colorspace != cache_info->colorspace) ||
2042 (image->columns != cache_info->columns) ||
2043 (image->rows != cache_info->rows) ||
2044 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2045 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2046 return(MagickFalse);
2047 return(MagickTrue);
2048}
2049
cristy77ff0282010-09-13 00:51:10 +00002050static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2051 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002052{
2053 CacheInfo
2054 *cache_info;
2055
cristy3ed852e2009-09-05 21:47:34 +00002056 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002057 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002058 status;
2059
cristy50a10922010-02-15 18:35:25 +00002060 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002061 cpu_throttle = 0,
2062 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002063 time_limit = 0;
2064
cristy1ea34962010-07-01 19:49:21 +00002065 static time_t
cristya21afde2010-07-02 00:45:40 +00002066 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002067
cristyc4f9f132010-03-04 18:50:01 +00002068 status=MagickTrue;
2069 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002070 if (cpu_throttle == 0)
2071 {
2072 char
2073 *limit;
2074
2075 /*
2076 Set CPU throttle in milleseconds.
2077 */
2078 cpu_throttle=MagickResourceInfinity;
2079 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2080 if (limit == (char *) NULL)
2081 limit=GetPolicyValue("throttle");
2082 if (limit != (char *) NULL)
2083 {
2084 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2085 limit=DestroyString(limit);
2086 }
2087 }
2088 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2089 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002090 if (time_limit == 0)
2091 {
cristy6ebe97c2010-07-03 01:17:28 +00002092 /*
2093 Set the exire time in seconds.
2094 */
cristy1ea34962010-07-01 19:49:21 +00002095 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002096 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002097 }
2098 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002099 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002100 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002101 assert(image->cache != (Cache) NULL);
2102 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002103 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002104 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002105 {
cristyaaa0cb62010-02-15 17:47:27 +00002106 LockSemaphoreInfo(cache_info->semaphore);
2107 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002108 {
cristyaaa0cb62010-02-15 17:47:27 +00002109 Image
2110 clone_image;
2111
2112 CacheInfo
2113 *clone_info;
2114
2115 /*
2116 Clone pixel cache.
2117 */
2118 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002119 clone_image.semaphore=AllocateSemaphoreInfo();
2120 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002121 clone_image.cache=ClonePixelCache(cache_info);
2122 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002123 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002124 if (status != MagickFalse)
2125 {
cristyabd6e372010-09-15 19:11:26 +00002126 if (clone != MagickFalse)
2127 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002128 if (status != MagickFalse)
2129 {
cristyabd6e372010-09-15 19:11:26 +00002130 destroy=MagickTrue;
2131 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002132 }
2133 }
cristy93505cf2010-08-10 21:37:49 +00002134 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002135 }
cristyaaa0cb62010-02-15 17:47:27 +00002136 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002137 }
cristy4320e0e2009-09-10 15:00:08 +00002138 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002139 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002140 if (status != MagickFalse)
2141 {
2142 /*
2143 Ensure the image matches the pixel cache morphology.
2144 */
2145 image->taint=MagickTrue;
2146 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002147 if (image->colorspace == GRAYColorspace)
2148 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002149 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2150 status=OpenPixelCache(image,IOMode,exception);
2151 }
cristyf84a1932010-01-03 18:00:18 +00002152 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002153 if (status == MagickFalse)
2154 return((Cache) NULL);
2155 return(image->cache);
2156}
2157
2158/*
2159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2160% %
2161% %
2162% %
2163% G e t O n e A u t h e n t i c P i x e l %
2164% %
2165% %
2166% %
2167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2168%
2169% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2170% location. The image background color is returned if an error occurs.
2171%
2172% The format of the GetOneAuthenticPixel() method is:
2173%
cristybb503372010-05-27 20:51:26 +00002174% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2175% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002176%
2177% A description of each parameter follows:
2178%
2179% o image: the image.
2180%
2181% o x,y: These values define the location of the pixel to return.
2182%
2183% o pixel: return a pixel at the specified (x,y) location.
2184%
2185% o exception: return any errors or warnings in this structure.
2186%
2187*/
cristyacbbb7c2010-06-30 18:56:48 +00002188MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2189 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002190{
2191 CacheInfo
2192 *cache_info;
2193
cristy2036f5c2010-09-19 21:18:17 +00002194 PixelPacket
2195 *pixels;
2196
cristy3ed852e2009-09-05 21:47:34 +00002197 assert(image != (Image *) NULL);
2198 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002199 assert(image->cache != (Cache) NULL);
2200 cache_info=(CacheInfo *) image->cache;
2201 assert(cache_info->signature == MagickSignature);
2202 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002203 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2204 (GetOneAuthenticPixelFromHandler) NULL)
2205 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2206 pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002207 *pixel=image->background_color;
2208 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2209 if (pixels == (PixelPacket *) NULL)
2210 return(MagickFalse);
2211 *pixel=(*pixels);
2212 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002213}
2214
2215/*
2216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2217% %
2218% %
2219% %
2220+ 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 %
2221% %
2222% %
2223% %
2224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2225%
2226% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2227% location. The image background color is returned if an error occurs.
2228%
2229% The format of the GetOneAuthenticPixelFromCache() method is:
2230%
2231% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002232% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2233% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002234%
2235% A description of each parameter follows:
2236%
2237% o image: the image.
2238%
2239% o x,y: These values define the location of the pixel to return.
2240%
2241% o pixel: return a pixel at the specified (x,y) location.
2242%
2243% o exception: return any errors or warnings in this structure.
2244%
2245*/
2246static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002247 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002248{
2249 PixelPacket
2250 *pixels;
2251
cristy0158a4b2010-09-20 13:59:45 +00002252 assert(image != (const Image *) NULL);
2253 assert(image->signature == MagickSignature);
2254 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002255 *pixel=image->background_color;
cristye7cc7cf2010-09-21 13:26:47 +00002256 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
cristy3ed852e2009-09-05 21:47:34 +00002257 if (pixels == (PixelPacket *) NULL)
2258 return(MagickFalse);
2259 *pixel=(*pixels);
2260 return(MagickTrue);
2261}
2262
2263/*
2264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2265% %
2266% %
2267% %
2268% G e t O n e V i r t u a l M a g i c k P i x e l %
2269% %
2270% %
2271% %
2272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273%
2274% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2275% location. The image background color is returned if an error occurs. If
2276% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2277%
2278% The format of the GetOneVirtualMagickPixel() method is:
2279%
2280% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002281% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002282% ExceptionInfo exception)
2283%
2284% A description of each parameter follows:
2285%
2286% o image: the image.
2287%
2288% o x,y: these values define the location of the pixel to return.
2289%
2290% o pixel: return a pixel at the specified (x,y) location.
2291%
2292% o exception: return any errors or warnings in this structure.
2293%
2294*/
2295MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002296 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2297 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002298{
2299 CacheInfo
2300 *cache_info;
2301
cristy0158a4b2010-09-20 13:59:45 +00002302 const int
2303 id = GetOpenMPThreadId();
2304
cristy3ed852e2009-09-05 21:47:34 +00002305 register const IndexPacket
2306 *indexes;
2307
2308 register const PixelPacket
cristy0158a4b2010-09-20 13:59:45 +00002309 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002310
2311 assert(image != (const Image *) NULL);
2312 assert(image->signature == MagickSignature);
2313 assert(image->cache != (Cache) NULL);
2314 cache_info=(CacheInfo *) image->cache;
2315 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002316 assert(id < (int) cache_info->number_threads);
2317 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2318 1UL,1UL,cache_info->nexus_info[id],exception);
cristye7cc7cf2010-09-21 13:26:47 +00002319 GetMagickPixelPacket(image,pixel);
cristy0158a4b2010-09-20 13:59:45 +00002320 if (pixels == (const PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002321 return(MagickFalse);
cristye7cc7cf2010-09-21 13:26:47 +00002322 indexes=GetVirtualIndexQueue(image);
cristy0158a4b2010-09-20 13:59:45 +00002323 SetMagickPixelPacket(image,pixels,indexes,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002324 return(MagickTrue);
2325}
2326
2327/*
2328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2329% %
2330% %
2331% %
2332% G e t O n e V i r t u a l M e t h o d P i x e l %
2333% %
2334% %
2335% %
2336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337%
2338% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2339% location as defined by specified pixel method. The image background color
2340% is returned if an error occurs. If you plan to modify the pixel, use
2341% GetOneAuthenticPixel() instead.
2342%
2343% The format of the GetOneVirtualMethodPixel() method is:
2344%
2345% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002346% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2347% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002348%
2349% A description of each parameter follows:
2350%
2351% o image: the image.
2352%
2353% o virtual_pixel_method: the virtual pixel method.
2354%
2355% o x,y: These values define the location of the pixel to return.
2356%
2357% o pixel: return a pixel at the specified (x,y) location.
2358%
2359% o exception: return any errors or warnings in this structure.
2360%
2361*/
2362MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002363 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002364 PixelPacket *pixel,ExceptionInfo *exception)
2365{
cristy3ed852e2009-09-05 21:47:34 +00002366 CacheInfo
2367 *cache_info;
2368
cristy0158a4b2010-09-20 13:59:45 +00002369 const int
2370 id = GetOpenMPThreadId();
2371
cristy2036f5c2010-09-19 21:18:17 +00002372 const PixelPacket
2373 *pixels;
2374
cristy3ed852e2009-09-05 21:47:34 +00002375 assert(image != (const Image *) NULL);
2376 assert(image->signature == MagickSignature);
2377 assert(image->cache != (Cache) NULL);
2378 cache_info=(CacheInfo *) image->cache;
2379 assert(cache_info->signature == MagickSignature);
2380 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002381 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2382 (GetOneVirtualPixelFromHandler) NULL)
2383 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2384 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002385 assert(id < (int) cache_info->number_threads);
2386 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2387 cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002388 if (pixels == (const PixelPacket *) NULL)
2389 return(MagickFalse);
2390 *pixel=(*pixels);
2391 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002392}
2393
2394/*
2395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2396% %
2397% %
2398% %
2399% G e t O n e V i r t u a l P i x e l %
2400% %
2401% %
2402% %
2403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2404%
2405% GetOneVirtualPixel() returns a single virtual pixel at the specified
2406% (x,y) location. The image background color is returned if an error occurs.
2407% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2408%
2409% The format of the GetOneVirtualPixel() method is:
2410%
cristybb503372010-05-27 20:51:26 +00002411% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2412% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002413%
2414% A description of each parameter follows:
2415%
2416% o image: the image.
2417%
2418% o x,y: These values define the location of the pixel to return.
2419%
2420% o pixel: return a pixel at the specified (x,y) location.
2421%
2422% o exception: return any errors or warnings in this structure.
2423%
2424*/
2425MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002426 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002427{
cristy3ed852e2009-09-05 21:47:34 +00002428 CacheInfo
2429 *cache_info;
2430
cristy0158a4b2010-09-20 13:59:45 +00002431 const int
2432 id = GetOpenMPThreadId();
2433
cristy2036f5c2010-09-19 21:18:17 +00002434 const PixelPacket
2435 *pixels;
2436
cristy3ed852e2009-09-05 21:47:34 +00002437 assert(image != (const Image *) NULL);
2438 assert(image->signature == MagickSignature);
2439 assert(image->cache != (Cache) NULL);
2440 cache_info=(CacheInfo *) image->cache;
2441 assert(cache_info->signature == MagickSignature);
2442 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002443 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2444 (GetOneVirtualPixelFromHandler) NULL)
2445 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2446 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002447 assert(id < (int) cache_info->number_threads);
2448 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2449 1UL,1UL,cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002450 if (pixels == (const PixelPacket *) NULL)
2451 return(MagickFalse);
2452 *pixel=(*pixels);
2453 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002454}
2455
2456/*
2457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2458% %
2459% %
2460% %
2461+ 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 %
2462% %
2463% %
2464% %
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466%
2467% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2468% specified (x,y) location. The image background color is returned if an
2469% error occurs.
2470%
2471% The format of the GetOneVirtualPixelFromCache() method is:
2472%
2473% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002474% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002475% PixelPacket *pixel,ExceptionInfo *exception)
2476%
2477% A description of each parameter follows:
2478%
2479% o image: the image.
2480%
2481% o virtual_pixel_method: the virtual pixel method.
2482%
2483% o x,y: These values define the location of the pixel to return.
2484%
2485% o pixel: return a pixel at the specified (x,y) location.
2486%
2487% o exception: return any errors or warnings in this structure.
2488%
2489*/
2490static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002491 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002492 PixelPacket *pixel,ExceptionInfo *exception)
2493{
cristy0158a4b2010-09-20 13:59:45 +00002494 CacheInfo
2495 *cache_info;
2496
2497 const int
2498 id = GetOpenMPThreadId();
2499
cristy3ed852e2009-09-05 21:47:34 +00002500 const PixelPacket
2501 *pixels;
2502
cristye7cc7cf2010-09-21 13:26:47 +00002503 assert(image != (const Image *) NULL);
2504 assert(image->signature == MagickSignature);
2505 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002506 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002507 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002508 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002509 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002510 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2511 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002512 if (pixels == (const PixelPacket *) NULL)
2513 return(MagickFalse);
2514 *pixel=(*pixels);
2515 return(MagickTrue);
2516}
2517
2518/*
2519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2520% %
2521% %
2522% %
2523+ G e t P i x e l C a c h e C o l o r s p a c e %
2524% %
2525% %
2526% %
2527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2528%
2529% GetPixelCacheColorspace() returns the class type of the pixel cache.
2530%
2531% The format of the GetPixelCacheColorspace() method is:
2532%
2533% Colorspace GetPixelCacheColorspace(Cache cache)
2534%
2535% A description of each parameter follows:
2536%
2537% o cache: the pixel cache.
2538%
2539*/
2540MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2541{
2542 CacheInfo
2543 *cache_info;
2544
2545 assert(cache != (Cache) NULL);
2546 cache_info=(CacheInfo *) cache;
2547 assert(cache_info->signature == MagickSignature);
2548 if (cache_info->debug != MagickFalse)
2549 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2550 cache_info->filename);
2551 return(cache_info->colorspace);
2552}
2553
2554/*
2555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2556% %
2557% %
2558% %
2559+ G e t P i x e l C a c h e M e t h o d s %
2560% %
2561% %
2562% %
2563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2564%
2565% GetPixelCacheMethods() initializes the CacheMethods structure.
2566%
2567% The format of the GetPixelCacheMethods() method is:
2568%
2569% void GetPixelCacheMethods(CacheMethods *cache_methods)
2570%
2571% A description of each parameter follows:
2572%
2573% o cache_methods: Specifies a pointer to a CacheMethods structure.
2574%
2575*/
2576MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2577{
2578 assert(cache_methods != (CacheMethods *) NULL);
2579 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2580 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2581 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2582 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2583 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2584 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2585 cache_methods->get_authentic_indexes_from_handler=
2586 GetAuthenticIndexesFromCache;
2587 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2588 cache_methods->get_one_authentic_pixel_from_handler=
2589 GetOneAuthenticPixelFromCache;
2590 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2591 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2592 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2593}
2594
2595/*
2596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2597% %
2598% %
2599% %
2600+ G e t P i x e l C a c h e N e x u s E x t e n t %
2601% %
2602% %
2603% %
2604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2605%
2606% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2607% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2608%
2609% The format of the GetPixelCacheNexusExtent() method is:
2610%
2611% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2612% NexusInfo *nexus_info)
2613%
2614% A description of each parameter follows:
2615%
2616% o nexus_info: the nexus info.
2617%
2618*/
2619MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2620 NexusInfo *nexus_info)
2621{
2622 CacheInfo
2623 *cache_info;
2624
2625 MagickSizeType
2626 extent;
2627
cristye7cc7cf2010-09-21 13:26:47 +00002628 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002629 cache_info=(CacheInfo *) cache;
2630 assert(cache_info->signature == MagickSignature);
2631 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2632 if (extent == 0)
2633 return((MagickSizeType) cache_info->columns*cache_info->rows);
2634 return(extent);
2635}
2636
2637/*
2638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2639% %
2640% %
2641% %
2642+ G e t P i x e l C a c h e N e x u s I n d e x e s %
2643% %
2644% %
2645% %
2646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2647%
2648% GetPixelCacheNexusIndexes() returns the indexes associated with the
2649% specified cache nexus.
2650%
2651% The format of the GetPixelCacheNexusIndexes() method is:
2652%
2653% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2654% NexusInfo *nexus_info)
2655%
2656% A description of each parameter follows:
2657%
2658% o cache: the pixel cache.
2659%
2660% o nexus_info: the cache nexus to return the colormap indexes.
2661%
2662*/
2663MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2664 NexusInfo *nexus_info)
2665{
2666 CacheInfo
2667 *cache_info;
2668
cristye7cc7cf2010-09-21 13:26:47 +00002669 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002670 cache_info=(CacheInfo *) cache;
2671 assert(cache_info->signature == MagickSignature);
2672 if (cache_info->storage_class == UndefinedClass)
2673 return((IndexPacket *) NULL);
2674 return(nexus_info->indexes);
2675}
2676
2677/*
2678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2679% %
2680% %
2681% %
2682+ G e t P i x e l C a c h e N e x u s P i x e l s %
2683% %
2684% %
2685% %
2686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2687%
2688% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2689% cache nexus.
2690%
2691% The format of the GetPixelCacheNexusPixels() method is:
2692%
2693% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2694% NexusInfo *nexus_info)
2695%
2696% A description of each parameter follows:
2697%
2698% o cache: the pixel cache.
2699%
2700% o nexus_info: the cache nexus to return the pixels.
2701%
2702*/
2703MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2704 NexusInfo *nexus_info)
2705{
2706 CacheInfo
2707 *cache_info;
2708
cristye7cc7cf2010-09-21 13:26:47 +00002709 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002710 cache_info=(CacheInfo *) cache;
2711 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002712 if (cache_info->storage_class == UndefinedClass)
2713 return((PixelPacket *) NULL);
2714 return(nexus_info->pixels);
2715}
2716
2717/*
2718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719% %
2720% %
2721% %
cristy056ba772010-01-02 23:33:54 +00002722+ G e t P i x e l C a c h e P i x e l s %
2723% %
2724% %
2725% %
2726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2727%
2728% GetPixelCachePixels() returns the pixels associated with the specified image.
2729%
2730% The format of the GetPixelCachePixels() method is:
2731%
cristyf84a1932010-01-03 18:00:18 +00002732% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2733% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002734%
2735% A description of each parameter follows:
2736%
2737% o image: the image.
2738%
2739% o length: the pixel cache length.
2740%
cristyf84a1932010-01-03 18:00:18 +00002741% o exception: return any errors or warnings in this structure.
2742%
cristy056ba772010-01-02 23:33:54 +00002743*/
cristyf84a1932010-01-03 18:00:18 +00002744MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2745 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002746{
2747 CacheInfo
2748 *cache_info;
2749
2750 assert(image != (const Image *) NULL);
2751 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002752 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002753 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002754 assert(cache_info->signature == MagickSignature);
2755 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002756 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002757 return((void *) NULL);
2758 *length=cache_info->length;
2759 return((void *) cache_info->pixels);
2760}
2761
2762/*
2763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2764% %
2765% %
2766% %
cristyb32b90a2009-09-07 21:45:48 +00002767+ 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 +00002768% %
2769% %
2770% %
2771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2772%
2773% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2774%
2775% The format of the GetPixelCacheStorageClass() method is:
2776%
2777% ClassType GetPixelCacheStorageClass(Cache cache)
2778%
2779% A description of each parameter follows:
2780%
2781% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2782%
2783% o cache: the pixel cache.
2784%
2785*/
2786MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2787{
2788 CacheInfo
2789 *cache_info;
2790
2791 assert(cache != (Cache) NULL);
2792 cache_info=(CacheInfo *) cache;
2793 assert(cache_info->signature == MagickSignature);
2794 if (cache_info->debug != MagickFalse)
2795 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2796 cache_info->filename);
2797 return(cache_info->storage_class);
2798}
2799
2800/*
2801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802% %
2803% %
2804% %
cristyb32b90a2009-09-07 21:45:48 +00002805+ G e t P i x e l C a c h e T i l e S i z e %
2806% %
2807% %
2808% %
2809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2810%
2811% GetPixelCacheTileSize() returns the pixel cache tile size.
2812%
2813% The format of the GetPixelCacheTileSize() method is:
2814%
cristybb503372010-05-27 20:51:26 +00002815% void GetPixelCacheTileSize(const Image *image,size_t *width,
2816% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002817%
2818% A description of each parameter follows:
2819%
2820% o image: the image.
2821%
2822% o width: the optimize cache tile width in pixels.
2823%
2824% o height: the optimize cache tile height in pixels.
2825%
2826*/
cristybb503372010-05-27 20:51:26 +00002827MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2828 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002829{
cristyb32b90a2009-09-07 21:45:48 +00002830 assert(image != (Image *) NULL);
2831 assert(image->signature == MagickSignature);
2832 if (image->debug != MagickFalse)
2833 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyb32b90a2009-09-07 21:45:48 +00002834 *width=2048UL/sizeof(PixelPacket);
2835 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002836 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002837 *height=(*width);
2838}
2839
2840/*
2841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2842% %
2843% %
2844% %
2845+ G e t P i x e l C a c h e T y p e %
2846% %
2847% %
2848% %
2849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2850%
2851% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2852%
2853% The format of the GetPixelCacheType() method is:
2854%
2855% CacheType GetPixelCacheType(const Image *image)
2856%
2857% A description of each parameter follows:
2858%
2859% o image: the image.
2860%
2861*/
2862MagickExport CacheType GetPixelCacheType(const Image *image)
2863{
2864 CacheInfo
2865 *cache_info;
2866
2867 assert(image != (Image *) NULL);
2868 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002869 assert(image->cache != (Cache) NULL);
2870 cache_info=(CacheInfo *) image->cache;
2871 assert(cache_info->signature == MagickSignature);
2872 return(cache_info->type);
2873}
2874
2875/*
2876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2877% %
2878% %
2879% %
cristy3ed852e2009-09-05 21:47:34 +00002880+ 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 %
2881% %
2882% %
2883% %
2884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885%
2886% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2887% pixel cache. A virtual pixel is any pixel access that is outside the
2888% boundaries of the image cache.
2889%
2890% The format of the GetPixelCacheVirtualMethod() method is:
2891%
2892% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2893%
2894% A description of each parameter follows:
2895%
2896% o image: the image.
2897%
2898*/
2899MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2900{
2901 CacheInfo
2902 *cache_info;
2903
2904 assert(image != (Image *) NULL);
2905 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002906 assert(image->cache != (Cache) NULL);
2907 cache_info=(CacheInfo *) image->cache;
2908 assert(cache_info->signature == MagickSignature);
2909 return(cache_info->virtual_pixel_method);
2910}
2911
2912/*
2913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2914% %
2915% %
2916% %
2917+ G e t V i r t u a l I n d e x e s F r o m C a c h e %
2918% %
2919% %
2920% %
2921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2922%
2923% GetVirtualIndexesFromCache() returns the indexes associated with the last
2924% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2925%
2926% The format of the GetVirtualIndexesFromCache() method is:
2927%
2928% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2929%
2930% A description of each parameter follows:
2931%
2932% o image: the image.
2933%
2934*/
2935static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2936{
2937 CacheInfo
2938 *cache_info;
2939
cristy5c9e6f22010-09-17 17:31:01 +00002940 const int
2941 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002942
cristye7cc7cf2010-09-21 13:26:47 +00002943 assert(image != (const Image *) NULL);
2944 assert(image->signature == MagickSignature);
2945 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002946 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002947 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002948 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002949 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002950}
2951
2952/*
2953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2954% %
2955% %
2956% %
2957+ G e t V i r t u a l I n d e x e s F r o m N e x u s %
2958% %
2959% %
2960% %
2961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2962%
2963% GetVirtualIndexesFromNexus() returns the indexes associated with the
2964% specified cache nexus.
2965%
2966% The format of the GetVirtualIndexesFromNexus() method is:
2967%
2968% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2969% NexusInfo *nexus_info)
2970%
2971% A description of each parameter follows:
2972%
2973% o cache: the pixel cache.
2974%
2975% o nexus_info: the cache nexus to return the colormap indexes.
2976%
2977*/
2978MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2979 NexusInfo *nexus_info)
2980{
2981 CacheInfo
2982 *cache_info;
2983
cristye7cc7cf2010-09-21 13:26:47 +00002984 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002985 cache_info=(CacheInfo *) cache;
2986 assert(cache_info->signature == MagickSignature);
2987 if (cache_info->storage_class == UndefinedClass)
2988 return((IndexPacket *) NULL);
2989 return(nexus_info->indexes);
2990}
2991
2992/*
2993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2994% %
2995% %
2996% %
2997% G e t V i r t u a l I n d e x Q u e u e %
2998% %
2999% %
3000% %
3001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3002%
3003% GetVirtualIndexQueue() returns the virtual black channel or the
3004% colormap indexes associated with the last call to QueueAuthenticPixels() or
3005% GetVirtualPixels(). NULL is returned if the black channel or colormap
3006% indexes are not available.
3007%
3008% The format of the GetVirtualIndexQueue() method is:
3009%
3010% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3011%
3012% A description of each parameter follows:
3013%
3014% o image: the image.
3015%
3016*/
3017MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3018{
3019 CacheInfo
3020 *cache_info;
3021
cristy2036f5c2010-09-19 21:18:17 +00003022 const int
3023 id = GetOpenMPThreadId();
3024
cristy3ed852e2009-09-05 21:47:34 +00003025 assert(image != (const Image *) NULL);
3026 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003027 assert(image->cache != (Cache) NULL);
3028 cache_info=(CacheInfo *) image->cache;
3029 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003030 if (cache_info->methods.get_virtual_indexes_from_handler !=
3031 (GetVirtualIndexesFromHandler) NULL)
3032 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003033 assert(id < (int) cache_info->number_threads);
3034 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003035}
3036
3037/*
3038%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3039% %
3040% %
3041% %
3042+ 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 %
3043% %
3044% %
3045% %
3046%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3047%
3048% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3049% pixel cache as defined by the geometry parameters. A pointer to the pixels
3050% is returned if the pixels are transferred, otherwise a NULL is returned.
3051%
3052% The format of the GetVirtualPixelsFromNexus() method is:
3053%
3054% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003055% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003056% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3057% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003058%
3059% A description of each parameter follows:
3060%
3061% o image: the image.
3062%
3063% o virtual_pixel_method: the virtual pixel method.
3064%
3065% o x,y,columns,rows: These values define the perimeter of a region of
3066% pixels.
3067%
3068% o nexus_info: the cache nexus to acquire.
3069%
3070% o exception: return any errors or warnings in this structure.
3071%
3072*/
3073
cristybb503372010-05-27 20:51:26 +00003074static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003075 DitherMatrix[64] =
3076 {
3077 0, 48, 12, 60, 3, 51, 15, 63,
3078 32, 16, 44, 28, 35, 19, 47, 31,
3079 8, 56, 4, 52, 11, 59, 7, 55,
3080 40, 24, 36, 20, 43, 27, 39, 23,
3081 2, 50, 14, 62, 1, 49, 13, 61,
3082 34, 18, 46, 30, 33, 17, 45, 29,
3083 10, 58, 6, 54, 9, 57, 5, 53,
3084 42, 26, 38, 22, 41, 25, 37, 21
3085 };
3086
cristybb503372010-05-27 20:51:26 +00003087static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003088{
cristybb503372010-05-27 20:51:26 +00003089 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003090 index;
3091
3092 index=x+DitherMatrix[x & 0x07]-32L;
3093 if (index < 0L)
3094 return(0L);
cristybb503372010-05-27 20:51:26 +00003095 if (index >= (ssize_t) columns)
3096 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003097 return(index);
3098}
3099
cristybb503372010-05-27 20:51:26 +00003100static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003101{
cristybb503372010-05-27 20:51:26 +00003102 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003103 index;
3104
3105 index=y+DitherMatrix[y & 0x07]-32L;
3106 if (index < 0L)
3107 return(0L);
cristybb503372010-05-27 20:51:26 +00003108 if (index >= (ssize_t) rows)
3109 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003110 return(index);
3111}
3112
cristybb503372010-05-27 20:51:26 +00003113static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003114{
3115 if (x < 0L)
3116 return(0L);
cristybb503372010-05-27 20:51:26 +00003117 if (x >= (ssize_t) columns)
3118 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003119 return(x);
3120}
3121
cristybb503372010-05-27 20:51:26 +00003122static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003123{
3124 if (y < 0L)
3125 return(0L);
cristybb503372010-05-27 20:51:26 +00003126 if (y >= (ssize_t) rows)
3127 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003128 return(y);
3129}
3130
cristybb503372010-05-27 20:51:26 +00003131static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003132{
cristybb503372010-05-27 20:51:26 +00003133 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003134}
3135
cristybb503372010-05-27 20:51:26 +00003136static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003137{
cristybb503372010-05-27 20:51:26 +00003138 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003139}
3140
3141/*
3142 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3143 returns not only the quotient (tile the offset falls in) but also the positive
3144 remainer within that tile such that 0 <= remainder < extent. This method is
3145 essentially a ldiv() using a floored modulo division rather than the normal
3146 default truncated modulo division.
3147*/
cristybb503372010-05-27 20:51:26 +00003148static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3149 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003150{
3151 MagickModulo
3152 modulo;
3153
cristybb503372010-05-27 20:51:26 +00003154 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003155 if (offset < 0L)
3156 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003157 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003158 return(modulo);
3159}
3160
3161MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003162 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3163 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003164 ExceptionInfo *exception)
3165{
3166 CacheInfo
3167 *cache_info;
3168
cristyc3ec0d42010-04-07 01:18:08 +00003169 IndexPacket
3170 virtual_index;
3171
cristy3ed852e2009-09-05 21:47:34 +00003172 MagickOffsetType
3173 offset;
3174
3175 MagickSizeType
3176 length,
3177 number_pixels;
3178
3179 NexusInfo
3180 **virtual_nexus;
3181
3182 PixelPacket
3183 *pixels,
3184 virtual_pixel;
3185
3186 RectangleInfo
3187 region;
3188
3189 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003190 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003191
3192 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003193 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003194
3195 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003196 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003197
cristye076a6e2010-08-15 19:59:43 +00003198 register PixelPacket
3199 *restrict q;
3200
cristybb503372010-05-27 20:51:26 +00003201 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003202 u,
3203 v;
3204
cristy3ed852e2009-09-05 21:47:34 +00003205 /*
3206 Acquire pixels.
3207 */
cristye7cc7cf2010-09-21 13:26:47 +00003208 assert(image != (const Image *) NULL);
3209 assert(image->signature == MagickSignature);
3210 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003211 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003212 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003213 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003214 return((const PixelPacket *) NULL);
3215 region.x=x;
3216 region.y=y;
3217 region.width=columns;
3218 region.height=rows;
3219 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3220 if (pixels == (PixelPacket *) NULL)
3221 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003222 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3223 nexus_info->region.x;
3224 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3225 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003226 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3227 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003228 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3229 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003230 {
3231 MagickBooleanType
3232 status;
3233
3234 /*
3235 Pixel request is inside cache extents.
3236 */
3237 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3238 return(pixels);
3239 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3240 if (status == MagickFalse)
3241 return((const PixelPacket *) NULL);
3242 if ((cache_info->storage_class == PseudoClass) ||
3243 (cache_info->colorspace == CMYKColorspace))
3244 {
3245 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3246 if (status == MagickFalse)
3247 return((const PixelPacket *) NULL);
3248 }
3249 return(pixels);
3250 }
3251 /*
3252 Pixel request is outside cache extents.
3253 */
3254 q=pixels;
3255 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3256 virtual_nexus=AcquirePixelCacheNexus(1);
3257 if (virtual_nexus == (NexusInfo **) NULL)
3258 {
3259 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3260 "UnableToGetCacheNexus","`%s'",image->filename);
3261 return((const PixelPacket *) NULL);
3262 }
3263 switch (virtual_pixel_method)
3264 {
3265 case BlackVirtualPixelMethod:
3266 {
cristy4789f0d2010-01-10 00:01:06 +00003267 SetRedPixelComponent(&virtual_pixel,0);
3268 SetGreenPixelComponent(&virtual_pixel,0);
3269 SetBluePixelComponent(&virtual_pixel,0);
3270 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003271 break;
3272 }
3273 case GrayVirtualPixelMethod:
3274 {
cristy4789f0d2010-01-10 00:01:06 +00003275 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3276 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3277 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3278 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003279 break;
3280 }
3281 case TransparentVirtualPixelMethod:
3282 {
cristy4789f0d2010-01-10 00:01:06 +00003283 SetRedPixelComponent(&virtual_pixel,0);
3284 SetGreenPixelComponent(&virtual_pixel,0);
3285 SetBluePixelComponent(&virtual_pixel,0);
3286 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003287 break;
3288 }
3289 case MaskVirtualPixelMethod:
3290 case WhiteVirtualPixelMethod:
3291 {
cristy4789f0d2010-01-10 00:01:06 +00003292 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3293 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3294 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3295 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003296 break;
3297 }
3298 default:
3299 {
3300 virtual_pixel=image->background_color;
3301 break;
3302 }
3303 }
cristyc3ec0d42010-04-07 01:18:08 +00003304 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003305 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003306 {
cristybb503372010-05-27 20:51:26 +00003307 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003308 {
3309 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003310 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003311 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3312 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003313 {
3314 MagickModulo
3315 x_modulo,
3316 y_modulo;
3317
3318 /*
3319 Transfer a single pixel.
3320 */
3321 length=(MagickSizeType) 1;
3322 switch (virtual_pixel_method)
3323 {
3324 case BackgroundVirtualPixelMethod:
3325 case ConstantVirtualPixelMethod:
3326 case BlackVirtualPixelMethod:
3327 case GrayVirtualPixelMethod:
3328 case TransparentVirtualPixelMethod:
3329 case MaskVirtualPixelMethod:
3330 case WhiteVirtualPixelMethod:
3331 {
3332 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003333 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003334 break;
3335 }
3336 case EdgeVirtualPixelMethod:
3337 default:
3338 {
3339 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003340 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003341 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003342 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3343 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003344 break;
3345 }
3346 case RandomVirtualPixelMethod:
3347 {
3348 if (cache_info->random_info == (RandomInfo *) NULL)
3349 cache_info->random_info=AcquireRandomInfo();
3350 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003351 RandomX(cache_info->random_info,cache_info->columns),
3352 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003353 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003354 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3355 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003356 break;
3357 }
3358 case DitherVirtualPixelMethod:
3359 {
3360 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003361 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003362 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003363 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3364 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003365 break;
3366 }
3367 case TileVirtualPixelMethod:
3368 {
3369 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3370 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3371 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3372 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3373 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003374 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3375 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003376 break;
3377 }
3378 case MirrorVirtualPixelMethod:
3379 {
3380 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3381 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003382 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003383 x_modulo.remainder-1L;
3384 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3385 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003386 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003387 y_modulo.remainder-1L;
3388 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3389 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3390 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003391 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3392 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003393 break;
3394 }
3395 case CheckerTileVirtualPixelMethod:
3396 {
3397 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3398 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3399 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3400 {
3401 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003402 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003403 break;
3404 }
3405 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3406 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3407 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003408 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3409 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003410 break;
3411 }
3412 case HorizontalTileVirtualPixelMethod:
3413 {
cristybb503372010-05-27 20:51:26 +00003414 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003415 {
3416 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003417 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003418 break;
3419 }
3420 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3421 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3422 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3423 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3424 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003425 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3426 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003427 break;
3428 }
3429 case VerticalTileVirtualPixelMethod:
3430 {
cristybb503372010-05-27 20:51:26 +00003431 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003432 {
3433 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003434 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003435 break;
3436 }
3437 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3438 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3439 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3440 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3441 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003442 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3443 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003444 break;
3445 }
3446 case HorizontalTileEdgeVirtualPixelMethod:
3447 {
3448 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3449 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003450 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003451 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003452 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3453 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003454 break;
3455 }
3456 case VerticalTileEdgeVirtualPixelMethod:
3457 {
3458 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3459 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003460 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003461 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003462 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3463 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003464 break;
3465 }
3466 }
3467 if (p == (const PixelPacket *) NULL)
3468 break;
3469 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003470 if ((indexes != (IndexPacket *) NULL) &&
3471 (virtual_indexes != (const IndexPacket *) NULL))
3472 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003473 continue;
3474 }
3475 /*
3476 Transfer a run of pixels.
3477 */
3478 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003479 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003480 if (p == (const PixelPacket *) NULL)
3481 break;
cristyc3ec0d42010-04-07 01:18:08 +00003482 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy8f036fe2010-09-18 02:02:00 +00003483 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003484 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003485 if ((indexes != (IndexPacket *) NULL) &&
3486 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003487 {
cristy8f036fe2010-09-18 02:02:00 +00003488 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003489 sizeof(*virtual_indexes));
3490 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003491 }
3492 }
3493 }
3494 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3495 return(pixels);
3496}
3497
3498/*
3499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3500% %
3501% %
3502% %
3503+ G e t V i r t u a l P i x e l C a c h e %
3504% %
3505% %
3506% %
3507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3508%
3509% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3510% cache as defined by the geometry parameters. A pointer to the pixels
3511% is returned if the pixels are transferred, otherwise a NULL is returned.
3512%
3513% The format of the GetVirtualPixelCache() method is:
3514%
3515% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003516% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3517% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003518% ExceptionInfo *exception)
3519%
3520% A description of each parameter follows:
3521%
3522% o image: the image.
3523%
3524% o virtual_pixel_method: the virtual pixel method.
3525%
3526% o x,y,columns,rows: These values define the perimeter of a region of
3527% pixels.
3528%
3529% o exception: return any errors or warnings in this structure.
3530%
3531*/
3532static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003533 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3534 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003535{
3536 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003537 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003538
cristy5c9e6f22010-09-17 17:31:01 +00003539 const int
3540 id = GetOpenMPThreadId();
3541
cristye7cc7cf2010-09-21 13:26:47 +00003542 assert(image != (const Image *) NULL);
3543 assert(image->signature == MagickSignature);
3544 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003545 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003546 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003547 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003548 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3549 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003550}
3551
3552/*
3553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3554% %
3555% %
3556% %
3557% G e t V i r t u a l P i x e l Q u e u e %
3558% %
3559% %
3560% %
3561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562%
3563% GetVirtualPixelQueue() returns the virtual pixels associated with the
3564% last call to QueueAuthenticPixels() or GetVirtualPixels().
3565%
3566% The format of the GetVirtualPixelQueue() method is:
3567%
3568% const PixelPacket *GetVirtualPixelQueue(const Image image)
3569%
3570% A description of each parameter follows:
3571%
3572% o image: the image.
3573%
3574*/
3575MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3576{
3577 CacheInfo
3578 *cache_info;
3579
cristy2036f5c2010-09-19 21:18:17 +00003580 const int
3581 id = GetOpenMPThreadId();
3582
cristy3ed852e2009-09-05 21:47:34 +00003583 assert(image != (const Image *) NULL);
3584 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003585 assert(image->cache != (Cache) NULL);
3586 cache_info=(CacheInfo *) image->cache;
3587 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003588 if (cache_info->methods.get_virtual_pixels_handler !=
3589 (GetVirtualPixelsHandler) NULL)
3590 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003591 assert(id < (int) cache_info->number_threads);
3592 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003593}
3594
3595/*
3596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3597% %
3598% %
3599% %
3600% G e t V i r t u a l P i x e l s %
3601% %
3602% %
3603% %
3604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605%
3606% GetVirtualPixels() returns an immutable pixel region. If the
3607% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003608% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003609% copy of the pixels or it may point to the original pixels in memory.
3610% Performance is maximized if the selected region is part of one row, or one
3611% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003612% (without a copy) if the image is in memory, or in a memory-mapped file. The
3613% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003614%
3615% Pixels accessed via the returned pointer represent a simple array of type
3616% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3617% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3618% the black color component or to obtain the colormap indexes (of type
3619% IndexPacket) corresponding to the region.
3620%
3621% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3622%
3623% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3624% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3625% GetCacheViewAuthenticPixels() instead.
3626%
3627% The format of the GetVirtualPixels() method is:
3628%
cristybb503372010-05-27 20:51:26 +00003629% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3630% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003631% ExceptionInfo *exception)
3632%
3633% A description of each parameter follows:
3634%
3635% o image: the image.
3636%
3637% o x,y,columns,rows: These values define the perimeter of a region of
3638% pixels.
3639%
3640% o exception: return any errors or warnings in this structure.
3641%
3642*/
3643MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003644 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3645 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003646{
3647 CacheInfo
3648 *cache_info;
3649
cristy2036f5c2010-09-19 21:18:17 +00003650 const int
3651 id = GetOpenMPThreadId();
3652
cristy3ed852e2009-09-05 21:47:34 +00003653 assert(image != (const Image *) NULL);
3654 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003655 assert(image->cache != (Cache) NULL);
3656 cache_info=(CacheInfo *) image->cache;
3657 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003658 if (cache_info->methods.get_virtual_pixel_handler !=
3659 (GetVirtualPixelHandler) NULL)
3660 return(cache_info->methods.get_virtual_pixel_handler(image,
3661 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003662 assert(id < (int) cache_info->number_threads);
3663 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3664 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003665}
3666
3667/*
3668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3669% %
3670% %
3671% %
3672+ 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 %
3673% %
3674% %
3675% %
3676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3677%
3678% GetVirtualPixelsCache() returns the pixels associated with the last call
3679% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3680%
3681% The format of the GetVirtualPixelsCache() method is:
3682%
3683% PixelPacket *GetVirtualPixelsCache(const Image *image)
3684%
3685% A description of each parameter follows:
3686%
3687% o image: the image.
3688%
3689*/
3690static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3691{
3692 CacheInfo
3693 *cache_info;
3694
cristy5c9e6f22010-09-17 17:31:01 +00003695 const int
3696 id = GetOpenMPThreadId();
3697
cristye7cc7cf2010-09-21 13:26:47 +00003698 assert(image != (const Image *) NULL);
3699 assert(image->signature == MagickSignature);
3700 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003701 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003702 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003703 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003704 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003705}
3706
3707/*
3708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3709% %
3710% %
3711% %
3712+ G e t V i r t u a l P i x e l s N e x u s %
3713% %
3714% %
3715% %
3716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3717%
3718% GetVirtualPixelsNexus() returns the pixels associated with the specified
3719% cache nexus.
3720%
3721% The format of the GetVirtualPixelsNexus() method is:
3722%
3723% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3724% NexusInfo *nexus_info)
3725%
3726% A description of each parameter follows:
3727%
3728% o cache: the pixel cache.
3729%
3730% o nexus_info: the cache nexus to return the colormap pixels.
3731%
3732*/
3733MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3734 NexusInfo *nexus_info)
3735{
3736 CacheInfo
3737 *cache_info;
3738
cristye7cc7cf2010-09-21 13:26:47 +00003739 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003740 cache_info=(CacheInfo *) cache;
3741 assert(cache_info->signature == MagickSignature);
3742 if (cache_info->storage_class == UndefinedClass)
3743 return((PixelPacket *) NULL);
3744 return((const PixelPacket *) nexus_info->pixels);
3745}
3746
3747/*
3748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3749% %
3750% %
3751% %
3752+ M a s k P i x e l C a c h e N e x u s %
3753% %
3754% %
3755% %
3756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3757%
3758% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3759% The method returns MagickTrue if the pixel region is masked, otherwise
3760% MagickFalse.
3761%
3762% The format of the MaskPixelCacheNexus() method is:
3763%
3764% MagickBooleanType MaskPixelCacheNexus(Image *image,
3765% NexusInfo *nexus_info,ExceptionInfo *exception)
3766%
3767% A description of each parameter follows:
3768%
3769% o image: the image.
3770%
3771% o nexus_info: the cache nexus to clip.
3772%
3773% o exception: return any errors or warnings in this structure.
3774%
3775*/
3776
3777static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3778 const MagickRealType alpha,const MagickPixelPacket *q,
3779 const MagickRealType beta,MagickPixelPacket *composite)
3780{
3781 MagickRealType
3782 gamma;
3783
3784 if (alpha == TransparentOpacity)
3785 {
3786 *composite=(*q);
3787 return;
3788 }
3789 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3790 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3791 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3792 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3793 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3794 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3795 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3796}
3797
3798static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3799 ExceptionInfo *exception)
3800{
3801 CacheInfo
3802 *cache_info;
3803
3804 MagickPixelPacket
3805 alpha,
3806 beta;
3807
3808 MagickSizeType
3809 number_pixels;
3810
3811 NexusInfo
3812 **clip_nexus,
3813 **image_nexus;
3814
3815 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003816 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003817
3818 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003819 *restrict nexus_indexes,
3820 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003821
cristy3ed852e2009-09-05 21:47:34 +00003822 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003823 *restrict p,
3824 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003825
cristye076a6e2010-08-15 19:59:43 +00003826 register ssize_t
3827 i;
3828
cristy3ed852e2009-09-05 21:47:34 +00003829 /*
3830 Apply clip mask.
3831 */
3832 if (image->debug != MagickFalse)
3833 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3834 if (image->mask == (Image *) NULL)
3835 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003836 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003837 if (cache_info == (Cache) NULL)
3838 return(MagickFalse);
3839 image_nexus=AcquirePixelCacheNexus(1);
3840 clip_nexus=AcquirePixelCacheNexus(1);
3841 if ((image_nexus == (NexusInfo **) NULL) ||
3842 (clip_nexus == (NexusInfo **) NULL))
3843 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003844 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3845 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3846 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003847 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3848 q=nexus_info->pixels;
3849 nexus_indexes=nexus_info->indexes;
3850 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3851 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3852 nexus_info->region.height,clip_nexus[0],&image->exception);
3853 GetMagickPixelPacket(image,&alpha);
3854 GetMagickPixelPacket(image,&beta);
3855 number_pixels=(MagickSizeType) nexus_info->region.width*
3856 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003857 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003858 {
3859 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3860 break;
3861 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3862 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3863 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3864 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003865 q->red=ClampToQuantum(beta.red);
3866 q->green=ClampToQuantum(beta.green);
3867 q->blue=ClampToQuantum(beta.blue);
3868 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003869 if (cache_info->active_index_channel != MagickFalse)
3870 nexus_indexes[i]=indexes[i];
3871 p++;
3872 q++;
3873 r++;
3874 }
3875 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3876 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003877 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003878 return(MagickFalse);
3879 return(MagickTrue);
3880}
3881
3882/*
3883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3884% %
3885% %
3886% %
3887+ O p e n P i x e l C a c h e %
3888% %
3889% %
3890% %
3891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3892%
3893% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3894% dimensions, allocating space for the image pixels and optionally the
3895% colormap indexes, and memory mapping the cache if it is disk based. The
3896% cache nexus array is initialized as well.
3897%
3898% The format of the OpenPixelCache() method is:
3899%
3900% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3901% ExceptionInfo *exception)
3902%
3903% A description of each parameter follows:
3904%
3905% o image: the image.
3906%
3907% o mode: ReadMode, WriteMode, or IOMode.
3908%
3909% o exception: return any errors or warnings in this structure.
3910%
3911*/
3912
cristyd43a46b2010-01-21 02:13:41 +00003913static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003914{
3915 cache_info->mapped=MagickFalse;
3916 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3917 cache_info->length);
3918 if (cache_info->pixels == (PixelPacket *) NULL)
3919 {
3920 cache_info->mapped=MagickTrue;
3921 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3922 cache_info->length);
3923 }
3924}
3925
3926static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3927{
3928 CacheInfo
3929 *cache_info;
3930
3931 MagickOffsetType
3932 count,
3933 extent,
3934 offset;
3935
3936 cache_info=(CacheInfo *) image->cache;
3937 if (image->debug != MagickFalse)
3938 {
3939 char
3940 format[MaxTextExtent],
3941 message[MaxTextExtent];
3942
cristyb9080c92009-12-01 20:13:26 +00003943 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003944 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003945 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003946 cache_info->cache_filename,cache_info->file,format);
3947 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3948 }
3949 if (length != (MagickSizeType) ((MagickOffsetType) length))
3950 return(MagickFalse);
3951 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3952 if (extent < 0)
3953 return(MagickFalse);
3954 if ((MagickSizeType) extent >= length)
3955 return(MagickTrue);
3956 offset=(MagickOffsetType) length-1;
3957 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3958 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3959}
3960
3961static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3962 ExceptionInfo *exception)
3963{
3964 char
3965 format[MaxTextExtent],
3966 message[MaxTextExtent];
3967
3968 CacheInfo
3969 *cache_info,
3970 source_info;
3971
3972 MagickSizeType
3973 length,
3974 number_pixels;
3975
3976 MagickStatusType
3977 status;
3978
3979 size_t
cristye076a6e2010-08-15 19:59:43 +00003980 columns,
cristy3ed852e2009-09-05 21:47:34 +00003981 packet_size;
3982
cristye7cc7cf2010-09-21 13:26:47 +00003983 assert(image != (const Image *) NULL);
3984 assert(image->signature == MagickSignature);
3985 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003986 if (image->debug != MagickFalse)
3987 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3988 if ((image->columns == 0) || (image->rows == 0))
3989 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3990 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003991 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003992 source_info=(*cache_info);
3993 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003994 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3995 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003996 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003997 cache_info->rows=image->rows;
3998 cache_info->columns=image->columns;
3999 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4000 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004001 if (image->ping != MagickFalse)
4002 {
4003 cache_info->storage_class=image->storage_class;
4004 cache_info->colorspace=image->colorspace;
4005 cache_info->type=PingCache;
4006 cache_info->pixels=(PixelPacket *) NULL;
4007 cache_info->indexes=(IndexPacket *) NULL;
4008 cache_info->length=0;
4009 return(MagickTrue);
4010 }
cristy3ed852e2009-09-05 21:47:34 +00004011 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4012 packet_size=sizeof(PixelPacket);
4013 if (cache_info->active_index_channel != MagickFalse)
4014 packet_size+=sizeof(IndexPacket);
4015 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004016 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004017 if (cache_info->columns != columns)
4018 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4019 image->filename);
4020 cache_info->length=length;
4021 status=AcquireMagickResource(AreaResource,cache_info->length);
4022 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4023 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4024 {
4025 status=AcquireMagickResource(MemoryResource,cache_info->length);
4026 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4027 (cache_info->type == MemoryCache))
4028 {
cristyd43a46b2010-01-21 02:13:41 +00004029 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004030 if (cache_info->pixels == (PixelPacket *) NULL)
4031 cache_info->pixels=source_info.pixels;
4032 else
4033 {
4034 /*
4035 Create memory pixel cache.
4036 */
4037 if (image->debug != MagickFalse)
4038 {
cristy97e7a572009-12-05 15:07:53 +00004039 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004040 format);
cristy3ed852e2009-09-05 21:47:34 +00004041 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004042 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004043 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004044 (double) cache_info->columns,(double) cache_info->rows,
4045 format);
cristy3ed852e2009-09-05 21:47:34 +00004046 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4047 message);
4048 }
4049 cache_info->storage_class=image->storage_class;
4050 cache_info->colorspace=image->colorspace;
4051 cache_info->type=MemoryCache;
4052 cache_info->indexes=(IndexPacket *) NULL;
4053 if (cache_info->active_index_channel != MagickFalse)
4054 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4055 number_pixels);
4056 if (source_info.storage_class != UndefinedClass)
4057 {
4058 status|=ClonePixelCachePixels(cache_info,&source_info,
4059 exception);
4060 RelinquishPixelCachePixels(&source_info);
4061 }
4062 return(MagickTrue);
4063 }
4064 }
4065 RelinquishMagickResource(MemoryResource,cache_info->length);
4066 }
4067 /*
4068 Create pixel cache on disk.
4069 */
4070 status=AcquireMagickResource(DiskResource,cache_info->length);
4071 if (status == MagickFalse)
4072 {
4073 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4074 "CacheResourcesExhausted","`%s'",image->filename);
4075 return(MagickFalse);
4076 }
4077 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4078 {
4079 RelinquishMagickResource(DiskResource,cache_info->length);
4080 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4081 image->filename);
4082 return(MagickFalse);
4083 }
4084 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4085 cache_info->length);
4086 if (status == MagickFalse)
4087 {
4088 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4089 image->filename);
4090 return(MagickFalse);
4091 }
4092 cache_info->storage_class=image->storage_class;
4093 cache_info->colorspace=image->colorspace;
4094 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4095 status=AcquireMagickResource(AreaResource,cache_info->length);
4096 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4097 cache_info->type=DiskCache;
4098 else
4099 {
4100 status=AcquireMagickResource(MapResource,cache_info->length);
4101 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4102 (cache_info->type != MemoryCache))
4103 cache_info->type=DiskCache;
4104 else
4105 {
4106 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4107 cache_info->offset,(size_t) cache_info->length);
4108 if (cache_info->pixels == (PixelPacket *) NULL)
4109 {
4110 cache_info->pixels=source_info.pixels;
4111 cache_info->type=DiskCache;
4112 }
4113 else
4114 {
4115 /*
4116 Create file-backed memory-mapped pixel cache.
4117 */
4118 (void) ClosePixelCacheOnDisk(cache_info);
4119 cache_info->type=MapCache;
4120 cache_info->mapped=MagickTrue;
4121 cache_info->indexes=(IndexPacket *) NULL;
4122 if (cache_info->active_index_channel != MagickFalse)
4123 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4124 number_pixels);
4125 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4126 {
4127 status=ClonePixelCachePixels(cache_info,&source_info,
4128 exception);
4129 RelinquishPixelCachePixels(&source_info);
4130 }
4131 if (image->debug != MagickFalse)
4132 {
cristy97e7a572009-12-05 15:07:53 +00004133 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004134 format);
cristy3ed852e2009-09-05 21:47:34 +00004135 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004136 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004137 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004138 cache_info->file,(double) cache_info->columns,(double)
4139 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004140 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4141 message);
4142 }
4143 return(MagickTrue);
4144 }
4145 }
4146 RelinquishMagickResource(MapResource,cache_info->length);
4147 }
4148 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4149 {
4150 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4151 RelinquishPixelCachePixels(&source_info);
4152 }
4153 if (image->debug != MagickFalse)
4154 {
cristyb9080c92009-12-01 20:13:26 +00004155 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004156 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004157 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4158 cache_info->cache_filename,cache_info->file,(double)
4159 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004160 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4161 }
4162 return(MagickTrue);
4163}
4164
4165/*
4166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4167% %
4168% %
4169% %
4170+ P e r s i s t P i x e l C a c h e %
4171% %
4172% %
4173% %
4174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4175%
4176% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4177% persistent pixel cache is one that resides on disk and is not destroyed
4178% when the program exits.
4179%
4180% The format of the PersistPixelCache() method is:
4181%
4182% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4183% const MagickBooleanType attach,MagickOffsetType *offset,
4184% ExceptionInfo *exception)
4185%
4186% A description of each parameter follows:
4187%
4188% o image: the image.
4189%
4190% o filename: the persistent pixel cache filename.
4191%
cristy01b7eb02009-09-10 23:10:14 +00004192% o attach: A value other than zero initializes the persistent pixel
4193% cache.
4194%
cristy3ed852e2009-09-05 21:47:34 +00004195% o initialize: A value other than zero initializes the persistent pixel
4196% cache.
4197%
4198% o offset: the offset in the persistent cache to store pixels.
4199%
4200% o exception: return any errors or warnings in this structure.
4201%
4202*/
4203MagickExport MagickBooleanType PersistPixelCache(Image *image,
4204 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4205 ExceptionInfo *exception)
4206{
4207 CacheInfo
4208 *cache_info,
4209 *clone_info;
4210
4211 Image
4212 clone_image;
4213
cristy3ed852e2009-09-05 21:47:34 +00004214 MagickBooleanType
4215 status;
4216
cristye076a6e2010-08-15 19:59:43 +00004217 ssize_t
4218 page_size;
4219
cristy3ed852e2009-09-05 21:47:34 +00004220 assert(image != (Image *) NULL);
4221 assert(image->signature == MagickSignature);
4222 if (image->debug != MagickFalse)
4223 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4224 assert(image->cache != (void *) NULL);
4225 assert(filename != (const char *) NULL);
4226 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004227 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004228 cache_info=(CacheInfo *) image->cache;
4229 assert(cache_info->signature == MagickSignature);
4230 if (attach != MagickFalse)
4231 {
4232 /*
cristy01b7eb02009-09-10 23:10:14 +00004233 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004234 */
4235 if (image->debug != MagickFalse)
4236 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004237 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004238 (void) CopyMagickString(cache_info->cache_filename,filename,
4239 MaxTextExtent);
4240 cache_info->type=DiskCache;
4241 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004242 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004243 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004244 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004245 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004246 }
cristy01b7eb02009-09-10 23:10:14 +00004247 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4248 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004249 {
cristyf84a1932010-01-03 18:00:18 +00004250 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004251 if ((cache_info->mode != ReadMode) &&
4252 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004253 (cache_info->reference_count == 1))
4254 {
4255 int
4256 status;
4257
4258 /*
cristy01b7eb02009-09-10 23:10:14 +00004259 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004260 */
4261 status=rename(cache_info->cache_filename,filename);
4262 if (status == 0)
4263 {
4264 (void) CopyMagickString(cache_info->cache_filename,filename,
4265 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004266 *offset+=cache_info->length+page_size-(cache_info->length %
4267 page_size);
cristyf84a1932010-01-03 18:00:18 +00004268 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004269 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004270 if (image->debug != MagickFalse)
4271 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4272 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004273 return(MagickTrue);
4274 }
4275 }
cristyf84a1932010-01-03 18:00:18 +00004276 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004277 }
4278 /*
cristy01b7eb02009-09-10 23:10:14 +00004279 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004280 */
4281 clone_image=(*image);
4282 clone_info=(CacheInfo *) clone_image.cache;
4283 image->cache=ClonePixelCache(cache_info);
4284 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4285 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4286 cache_info->type=DiskCache;
4287 cache_info->offset=(*offset);
4288 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004289 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004290 if (status != MagickFalse)
cristye7cc7cf2010-09-21 13:26:47 +00004291 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004292 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004293 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4294 return(status);
4295}
4296
4297/*
4298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4299% %
4300% %
4301% %
4302+ Q u e u e A u t h e n t i c N e x u s %
4303% %
4304% %
4305% %
4306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4307%
4308% QueueAuthenticNexus() allocates an region to store image pixels as defined
4309% by the region rectangle and returns a pointer to the region. This region is
4310% subsequently transferred from the pixel cache with
4311% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4312% pixels are transferred, otherwise a NULL is returned.
4313%
4314% The format of the QueueAuthenticNexus() method is:
4315%
cristy5f959472010-05-27 22:19:46 +00004316% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4317% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004318% NexusInfo *nexus_info,ExceptionInfo *exception)
4319%
4320% A description of each parameter follows:
4321%
4322% o image: the image.
4323%
4324% o x,y,columns,rows: These values define the perimeter of a region of
4325% pixels.
4326%
4327% o nexus_info: the cache nexus to set.
4328%
4329% o exception: return any errors or warnings in this structure.
4330%
4331*/
cristybb503372010-05-27 20:51:26 +00004332MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004333 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4334 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004335{
4336 CacheInfo
4337 *cache_info;
4338
4339 MagickOffsetType
4340 offset;
4341
4342 MagickSizeType
4343 number_pixels;
4344
4345 RectangleInfo
4346 region;
4347
4348 /*
4349 Validate pixel cache geometry.
4350 */
cristye7cc7cf2010-09-21 13:26:47 +00004351 assert(image != (const Image *) NULL);
4352 assert(image->signature == MagickSignature);
4353 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004354 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004355 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004356 if (cache_info == (Cache) NULL)
4357 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004358 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4359 {
4360 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4361 "NoPixelsDefinedInCache","`%s'",image->filename);
4362 return((PixelPacket *) NULL);
4363 }
cristybb503372010-05-27 20:51:26 +00004364 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4365 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004366 {
4367 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4368 "PixelsAreNotAuthentic","`%s'",image->filename);
4369 return((PixelPacket *) NULL);
4370 }
4371 offset=(MagickOffsetType) y*cache_info->columns+x;
4372 if (offset < 0)
4373 return((PixelPacket *) NULL);
4374 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4375 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4376 if ((MagickSizeType) offset >= number_pixels)
4377 return((PixelPacket *) NULL);
4378 /*
4379 Return pixel cache.
4380 */
4381 region.x=x;
4382 region.y=y;
4383 region.width=columns;
4384 region.height=rows;
4385 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4386}
4387
4388/*
4389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4390% %
4391% %
4392% %
4393+ 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 %
4394% %
4395% %
4396% %
4397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4398%
4399% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4400% defined by the region rectangle and returns a pointer to the region. This
4401% region is subsequently transferred from the pixel cache with
4402% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4403% pixels are transferred, otherwise a NULL is returned.
4404%
4405% The format of the QueueAuthenticPixelsCache() method is:
4406%
cristybb503372010-05-27 20:51:26 +00004407% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4408% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004409% ExceptionInfo *exception)
4410%
4411% A description of each parameter follows:
4412%
4413% o image: the image.
4414%
4415% o x,y,columns,rows: These values define the perimeter of a region of
4416% pixels.
4417%
4418% o exception: return any errors or warnings in this structure.
4419%
4420*/
cristybb503372010-05-27 20:51:26 +00004421static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4422 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004423 ExceptionInfo *exception)
4424{
4425 CacheInfo
4426 *cache_info;
4427
cristy5c9e6f22010-09-17 17:31:01 +00004428 const int
4429 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004430
cristye7cc7cf2010-09-21 13:26:47 +00004431 assert(image != (const Image *) NULL);
4432 assert(image->signature == MagickSignature);
4433 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004434 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004435 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004436 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004437 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4438 exception));
cristy3ed852e2009-09-05 21:47:34 +00004439}
4440
4441/*
4442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4443% %
4444% %
4445% %
4446% Q u e u e A u t h e n t i c P i x e l s %
4447% %
4448% %
4449% %
4450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4451%
4452% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4453% successfully intialized a pointer to a PixelPacket array representing the
4454% region is returned, otherwise NULL is returned. The returned pointer may
4455% point to a temporary working buffer for the pixels or it may point to the
4456% final location of the pixels in memory.
4457%
4458% Write-only access means that any existing pixel values corresponding to
4459% the region are ignored. This is useful if the initial image is being
4460% created from scratch, or if the existing pixel values are to be
4461% completely replaced without need to refer to their pre-existing values.
4462% The application is free to read and write the pixel buffer returned by
4463% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4464% initialize the pixel array values. Initializing pixel array values is the
4465% application's responsibility.
4466%
4467% Performance is maximized if the selected region is part of one row, or
4468% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004469% pixels in-place (without a copy) if the image is in memory, or in a
4470% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004471% by the user.
4472%
4473% Pixels accessed via the returned pointer represent a simple array of type
4474% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4475% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4476% the black color component or the colormap indexes (of type IndexPacket)
4477% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4478% array has been updated, the changes must be saved back to the underlying
4479% image using SyncAuthenticPixels() or they may be lost.
4480%
4481% The format of the QueueAuthenticPixels() method is:
4482%
cristy5f959472010-05-27 22:19:46 +00004483% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4484% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004485% ExceptionInfo *exception)
4486%
4487% A description of each parameter follows:
4488%
4489% o image: the image.
4490%
4491% o x,y,columns,rows: These values define the perimeter of a region of
4492% pixels.
4493%
4494% o exception: return any errors or warnings in this structure.
4495%
4496*/
cristybb503372010-05-27 20:51:26 +00004497MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4498 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004499 ExceptionInfo *exception)
4500{
4501 CacheInfo
4502 *cache_info;
4503
cristy2036f5c2010-09-19 21:18:17 +00004504 const int
4505 id = GetOpenMPThreadId();
4506
cristy3ed852e2009-09-05 21:47:34 +00004507 assert(image != (Image *) NULL);
4508 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004509 assert(image->cache != (Cache) NULL);
4510 cache_info=(CacheInfo *) image->cache;
4511 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004512 if (cache_info->methods.queue_authentic_pixels_handler !=
4513 (QueueAuthenticPixelsHandler) NULL)
4514 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4515 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004516 assert(id < (int) cache_info->number_threads);
4517 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4518 exception));
cristy3ed852e2009-09-05 21:47:34 +00004519}
4520
4521/*
4522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4523% %
4524% %
4525% %
4526+ R e a d P i x e l C a c h e I n d e x e s %
4527% %
4528% %
4529% %
4530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4531%
4532% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4533% the pixel cache.
4534%
4535% The format of the ReadPixelCacheIndexes() method is:
4536%
4537% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4538% NexusInfo *nexus_info,ExceptionInfo *exception)
4539%
4540% A description of each parameter follows:
4541%
4542% o cache_info: the pixel cache.
4543%
4544% o nexus_info: the cache nexus to read the colormap indexes.
4545%
4546% o exception: return any errors or warnings in this structure.
4547%
4548*/
4549static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4550 NexusInfo *nexus_info,ExceptionInfo *exception)
4551{
4552 MagickOffsetType
4553 count,
4554 offset;
4555
4556 MagickSizeType
4557 length,
4558 number_pixels;
4559
4560 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004561 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004562
cristybb503372010-05-27 20:51:26 +00004563 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004564 y;
4565
cristybb503372010-05-27 20:51:26 +00004566 size_t
cristy3ed852e2009-09-05 21:47:34 +00004567 rows;
4568
cristy3ed852e2009-09-05 21:47:34 +00004569 if (cache_info->active_index_channel == MagickFalse)
4570 return(MagickFalse);
4571 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4572 return(MagickTrue);
4573 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4574 nexus_info->region.x;
4575 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4576 rows=nexus_info->region.height;
4577 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004578 q=nexus_info->indexes;
4579 switch (cache_info->type)
4580 {
4581 case MemoryCache:
4582 case MapCache:
4583 {
4584 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004585 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004586
4587 /*
4588 Read indexes from memory.
4589 */
cristydd341db2010-03-04 19:06:38 +00004590 if ((cache_info->columns == nexus_info->region.width) &&
4591 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4592 {
4593 length=number_pixels;
4594 rows=1UL;
4595 }
cristy3ed852e2009-09-05 21:47:34 +00004596 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004597 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004598 {
cristy8f036fe2010-09-18 02:02:00 +00004599 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004600 p+=cache_info->columns;
4601 q+=nexus_info->region.width;
4602 }
4603 break;
4604 }
4605 case DiskCache:
4606 {
4607 /*
4608 Read indexes from disk.
4609 */
4610 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4611 {
4612 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4613 cache_info->cache_filename);
4614 return(MagickFalse);
4615 }
cristydd341db2010-03-04 19:06:38 +00004616 if ((cache_info->columns == nexus_info->region.width) &&
4617 (number_pixels < MagickMaxBufferExtent))
4618 {
4619 length=number_pixels;
4620 rows=1UL;
4621 }
cristy3ed852e2009-09-05 21:47:34 +00004622 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004623 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004624 {
4625 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4626 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4627 if ((MagickSizeType) count < length)
4628 break;
4629 offset+=cache_info->columns;
4630 q+=nexus_info->region.width;
4631 }
cristybb503372010-05-27 20:51:26 +00004632 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004633 {
4634 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4635 cache_info->cache_filename);
4636 return(MagickFalse);
4637 }
4638 break;
4639 }
4640 default:
4641 break;
4642 }
4643 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004644 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004645 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004646 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004647 nexus_info->region.width,(double) nexus_info->region.height,(double)
4648 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004649 return(MagickTrue);
4650}
4651
4652/*
4653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4654% %
4655% %
4656% %
4657+ R e a d P i x e l C a c h e P i x e l s %
4658% %
4659% %
4660% %
4661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4662%
4663% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4664% cache.
4665%
4666% The format of the ReadPixelCachePixels() method is:
4667%
4668% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4669% NexusInfo *nexus_info,ExceptionInfo *exception)
4670%
4671% A description of each parameter follows:
4672%
4673% o cache_info: the pixel cache.
4674%
4675% o nexus_info: the cache nexus to read the pixels.
4676%
4677% o exception: return any errors or warnings in this structure.
4678%
4679*/
4680static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4681 NexusInfo *nexus_info,ExceptionInfo *exception)
4682{
4683 MagickOffsetType
4684 count,
4685 offset;
4686
4687 MagickSizeType
4688 length,
4689 number_pixels;
4690
cristy3ed852e2009-09-05 21:47:34 +00004691 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004692 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004693
cristye076a6e2010-08-15 19:59:43 +00004694 register ssize_t
4695 y;
4696
cristybb503372010-05-27 20:51:26 +00004697 size_t
cristy3ed852e2009-09-05 21:47:34 +00004698 rows;
4699
cristy3ed852e2009-09-05 21:47:34 +00004700 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4701 return(MagickTrue);
4702 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4703 nexus_info->region.x;
4704 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4705 rows=nexus_info->region.height;
4706 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004707 q=nexus_info->pixels;
4708 switch (cache_info->type)
4709 {
4710 case MemoryCache:
4711 case MapCache:
4712 {
4713 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004714 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004715
4716 /*
4717 Read pixels from memory.
4718 */
cristydd341db2010-03-04 19:06:38 +00004719 if ((cache_info->columns == nexus_info->region.width) &&
4720 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4721 {
4722 length=number_pixels;
4723 rows=1UL;
4724 }
cristy3ed852e2009-09-05 21:47:34 +00004725 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004726 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004727 {
cristy8f036fe2010-09-18 02:02:00 +00004728 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004729 p+=cache_info->columns;
4730 q+=nexus_info->region.width;
4731 }
4732 break;
4733 }
4734 case DiskCache:
4735 {
4736 /*
4737 Read pixels from disk.
4738 */
4739 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4740 {
4741 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4742 cache_info->cache_filename);
4743 return(MagickFalse);
4744 }
cristydd341db2010-03-04 19:06:38 +00004745 if ((cache_info->columns == nexus_info->region.width) &&
4746 (number_pixels < MagickMaxBufferExtent))
4747 {
4748 length=number_pixels;
4749 rows=1UL;
4750 }
cristybb503372010-05-27 20:51:26 +00004751 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004752 {
4753 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4754 sizeof(*q),length,(unsigned char *) q);
4755 if ((MagickSizeType) count < length)
4756 break;
4757 offset+=cache_info->columns;
4758 q+=nexus_info->region.width;
4759 }
cristybb503372010-05-27 20:51:26 +00004760 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004761 {
4762 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4763 cache_info->cache_filename);
4764 return(MagickFalse);
4765 }
4766 break;
4767 }
4768 default:
4769 break;
4770 }
4771 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004772 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004773 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004774 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004775 nexus_info->region.width,(double) nexus_info->region.height,(double)
4776 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004777 return(MagickTrue);
4778}
4779
4780/*
4781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4782% %
4783% %
4784% %
4785+ R e f e r e n c e P i x e l C a c h e %
4786% %
4787% %
4788% %
4789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4790%
4791% ReferencePixelCache() increments the reference count associated with the
4792% pixel cache returning a pointer to the cache.
4793%
4794% The format of the ReferencePixelCache method is:
4795%
4796% Cache ReferencePixelCache(Cache cache_info)
4797%
4798% A description of each parameter follows:
4799%
4800% o cache_info: the pixel cache.
4801%
4802*/
4803MagickExport Cache ReferencePixelCache(Cache cache)
4804{
4805 CacheInfo
4806 *cache_info;
4807
4808 assert(cache != (Cache *) NULL);
4809 cache_info=(CacheInfo *) cache;
4810 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004811 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004812 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004813 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004814 return(cache_info);
4815}
4816
4817/*
4818%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4819% %
4820% %
4821% %
4822+ S e t P i x e l C a c h e M e t h o d s %
4823% %
4824% %
4825% %
4826%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4827%
4828% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4829%
4830% The format of the SetPixelCacheMethods() method is:
4831%
4832% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4833%
4834% A description of each parameter follows:
4835%
4836% o cache: the pixel cache.
4837%
4838% o cache_methods: Specifies a pointer to a CacheMethods structure.
4839%
4840*/
4841MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4842{
4843 CacheInfo
4844 *cache_info;
4845
4846 GetOneAuthenticPixelFromHandler
4847 get_one_authentic_pixel_from_handler;
4848
4849 GetOneVirtualPixelFromHandler
4850 get_one_virtual_pixel_from_handler;
4851
4852 /*
4853 Set cache pixel methods.
4854 */
4855 assert(cache != (Cache) NULL);
4856 assert(cache_methods != (CacheMethods *) NULL);
4857 cache_info=(CacheInfo *) cache;
4858 assert(cache_info->signature == MagickSignature);
4859 if (cache_info->debug != MagickFalse)
4860 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4861 cache_info->filename);
4862 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4863 cache_info->methods.get_virtual_pixel_handler=
4864 cache_methods->get_virtual_pixel_handler;
4865 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4866 cache_info->methods.destroy_pixel_handler=
4867 cache_methods->destroy_pixel_handler;
4868 if (cache_methods->get_virtual_indexes_from_handler !=
4869 (GetVirtualIndexesFromHandler) NULL)
4870 cache_info->methods.get_virtual_indexes_from_handler=
4871 cache_methods->get_virtual_indexes_from_handler;
4872 if (cache_methods->get_authentic_pixels_handler !=
4873 (GetAuthenticPixelsHandler) NULL)
4874 cache_info->methods.get_authentic_pixels_handler=
4875 cache_methods->get_authentic_pixels_handler;
4876 if (cache_methods->queue_authentic_pixels_handler !=
4877 (QueueAuthenticPixelsHandler) NULL)
4878 cache_info->methods.queue_authentic_pixels_handler=
4879 cache_methods->queue_authentic_pixels_handler;
4880 if (cache_methods->sync_authentic_pixels_handler !=
4881 (SyncAuthenticPixelsHandler) NULL)
4882 cache_info->methods.sync_authentic_pixels_handler=
4883 cache_methods->sync_authentic_pixels_handler;
4884 if (cache_methods->get_authentic_pixels_from_handler !=
4885 (GetAuthenticPixelsFromHandler) NULL)
4886 cache_info->methods.get_authentic_pixels_from_handler=
4887 cache_methods->get_authentic_pixels_from_handler;
4888 if (cache_methods->get_authentic_indexes_from_handler !=
4889 (GetAuthenticIndexesFromHandler) NULL)
4890 cache_info->methods.get_authentic_indexes_from_handler=
4891 cache_methods->get_authentic_indexes_from_handler;
4892 get_one_virtual_pixel_from_handler=
4893 cache_info->methods.get_one_virtual_pixel_from_handler;
4894 if (get_one_virtual_pixel_from_handler !=
4895 (GetOneVirtualPixelFromHandler) NULL)
4896 cache_info->methods.get_one_virtual_pixel_from_handler=
4897 cache_methods->get_one_virtual_pixel_from_handler;
4898 get_one_authentic_pixel_from_handler=
4899 cache_methods->get_one_authentic_pixel_from_handler;
4900 if (get_one_authentic_pixel_from_handler !=
4901 (GetOneAuthenticPixelFromHandler) NULL)
4902 cache_info->methods.get_one_authentic_pixel_from_handler=
4903 cache_methods->get_one_authentic_pixel_from_handler;
4904}
4905
4906/*
4907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4908% %
4909% %
4910% %
4911+ S e t P i x e l C a c h e N e x u s P i x e l s %
4912% %
4913% %
4914% %
4915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4916%
4917% SetPixelCacheNexusPixels() defines the region of the cache for the
4918% specified cache nexus.
4919%
4920% The format of the SetPixelCacheNexusPixels() method is:
4921%
4922% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4923% const RectangleInfo *region,NexusInfo *nexus_info,
4924% ExceptionInfo *exception)
4925%
4926% A description of each parameter follows:
4927%
4928% o image: the image.
4929%
4930% o region: A pointer to the RectangleInfo structure that defines the
4931% region of this particular cache nexus.
4932%
4933% o nexus_info: the cache nexus to set.
4934%
4935% o exception: return any errors or warnings in this structure.
4936%
4937*/
cristyabd6e372010-09-15 19:11:26 +00004938
4939static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4940 NexusInfo *nexus_info,ExceptionInfo *exception)
4941{
4942 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4943 return(MagickFalse);
4944 nexus_info->mapped=MagickFalse;
4945 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4946 nexus_info->length);
4947 if (nexus_info->cache == (PixelPacket *) NULL)
4948 {
4949 nexus_info->mapped=MagickTrue;
4950 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4951 nexus_info->length);
4952 }
4953 if (nexus_info->cache == (PixelPacket *) NULL)
4954 {
4955 (void) ThrowMagickException(exception,GetMagickModule(),
4956 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4957 cache_info->filename);
4958 return(MagickFalse);
4959 }
4960 return(MagickTrue);
4961}
4962
cristy3ed852e2009-09-05 21:47:34 +00004963static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4964 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4965{
4966 CacheInfo
4967 *cache_info;
4968
4969 MagickBooleanType
4970 status;
4971
cristy3ed852e2009-09-05 21:47:34 +00004972 MagickSizeType
4973 length,
4974 number_pixels;
4975
cristy3ed852e2009-09-05 21:47:34 +00004976 cache_info=(CacheInfo *) image->cache;
4977 assert(cache_info->signature == MagickSignature);
4978 if (cache_info->type == UndefinedCache)
4979 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004980 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004981 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4982 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004983 {
cristybb503372010-05-27 20:51:26 +00004984 ssize_t
cristybad067a2010-02-15 17:20:55 +00004985 x,
4986 y;
cristy3ed852e2009-09-05 21:47:34 +00004987
cristyeaedf062010-05-29 22:36:02 +00004988 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4989 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004990 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4991 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004992 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004993 ((nexus_info->region.width == cache_info->columns) ||
4994 ((nexus_info->region.width % cache_info->columns) == 0)))))
4995 {
4996 MagickOffsetType
4997 offset;
4998
4999 /*
5000 Pixels are accessed directly from memory.
5001 */
5002 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5003 nexus_info->region.x;
5004 nexus_info->pixels=cache_info->pixels+offset;
5005 nexus_info->indexes=(IndexPacket *) NULL;
5006 if (cache_info->active_index_channel != MagickFalse)
5007 nexus_info->indexes=cache_info->indexes+offset;
5008 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005009 }
5010 }
5011 /*
5012 Pixels are stored in a cache region until they are synced to the cache.
5013 */
5014 number_pixels=(MagickSizeType) nexus_info->region.width*
5015 nexus_info->region.height;
5016 length=number_pixels*sizeof(PixelPacket);
5017 if (cache_info->active_index_channel != MagickFalse)
5018 length+=number_pixels*sizeof(IndexPacket);
5019 if (nexus_info->cache == (PixelPacket *) NULL)
5020 {
5021 nexus_info->length=length;
5022 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5023 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005024 {
5025 nexus_info->length=0;
5026 return((PixelPacket *) NULL);
5027 }
cristy3ed852e2009-09-05 21:47:34 +00005028 }
5029 else
5030 if (nexus_info->length != length)
5031 {
5032 RelinquishCacheNexusPixels(nexus_info);
5033 nexus_info->length=length;
5034 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5035 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005036 {
5037 nexus_info->length=0;
5038 return((PixelPacket *) NULL);
5039 }
cristy3ed852e2009-09-05 21:47:34 +00005040 }
5041 nexus_info->pixels=nexus_info->cache;
5042 nexus_info->indexes=(IndexPacket *) NULL;
5043 if (cache_info->active_index_channel != MagickFalse)
5044 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5045 return(nexus_info->pixels);
5046}
5047
5048/*
5049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5050% %
5051% %
5052% %
5053% 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 %
5054% %
5055% %
5056% %
5057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5058%
5059% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5060% pixel cache and returns the previous setting. A virtual pixel is any pixel
5061% access that is outside the boundaries of the image cache.
5062%
5063% The format of the SetPixelCacheVirtualMethod() method is:
5064%
5065% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5066% const VirtualPixelMethod virtual_pixel_method)
5067%
5068% A description of each parameter follows:
5069%
5070% o image: the image.
5071%
5072% o virtual_pixel_method: choose the type of virtual pixel.
5073%
5074*/
5075MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5076 const VirtualPixelMethod virtual_pixel_method)
5077{
5078 CacheInfo
5079 *cache_info;
5080
5081 VirtualPixelMethod
5082 method;
5083
5084 assert(image != (Image *) NULL);
5085 assert(image->signature == MagickSignature);
5086 if (image->debug != MagickFalse)
5087 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5088 assert(image->cache != (Cache) NULL);
5089 cache_info=(CacheInfo *) image->cache;
5090 assert(cache_info->signature == MagickSignature);
5091 method=cache_info->virtual_pixel_method;
5092 cache_info->virtual_pixel_method=virtual_pixel_method;
5093 return(method);
5094}
5095
5096/*
5097%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5098% %
5099% %
5100% %
5101+ 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 %
5102% %
5103% %
5104% %
5105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5106%
5107% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5108% in-memory or disk cache. The method returns MagickTrue if the pixel region
5109% is synced, otherwise MagickFalse.
5110%
5111% The format of the SyncAuthenticPixelCacheNexus() method is:
5112%
5113% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5114% NexusInfo *nexus_info,ExceptionInfo *exception)
5115%
5116% A description of each parameter follows:
5117%
5118% o image: the image.
5119%
5120% o nexus_info: the cache nexus to sync.
5121%
5122% o exception: return any errors or warnings in this structure.
5123%
5124*/
5125MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5126 NexusInfo *nexus_info,ExceptionInfo *exception)
5127{
5128 CacheInfo
5129 *cache_info;
5130
5131 MagickBooleanType
5132 status;
5133
5134 /*
5135 Transfer pixels to the cache.
5136 */
5137 assert(image != (Image *) NULL);
5138 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005139 if (image->cache == (Cache) NULL)
5140 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5141 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005142 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005143 if (cache_info->type == UndefinedCache)
5144 return(MagickFalse);
5145 if ((image->clip_mask != (Image *) NULL) &&
5146 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5147 return(MagickFalse);
5148 if ((image->mask != (Image *) NULL) &&
5149 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5150 return(MagickFalse);
5151 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5152 return(MagickTrue);
5153 assert(cache_info->signature == MagickSignature);
5154 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5155 if ((cache_info->active_index_channel != MagickFalse) &&
5156 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5157 return(MagickFalse);
5158 return(status);
5159}
5160
5161/*
5162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5163% %
5164% %
5165% %
5166+ S y n c A u t h e n t i c P i x e l C a c h e %
5167% %
5168% %
5169% %
5170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5171%
5172% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5173% or disk cache. The method returns MagickTrue if the pixel region is synced,
5174% otherwise MagickFalse.
5175%
5176% The format of the SyncAuthenticPixelsCache() method is:
5177%
5178% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5179% ExceptionInfo *exception)
5180%
5181% A description of each parameter follows:
5182%
5183% o image: the image.
5184%
5185% o exception: return any errors or warnings in this structure.
5186%
5187*/
5188static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5189 ExceptionInfo *exception)
5190{
5191 CacheInfo
5192 *cache_info;
5193
cristy5c9e6f22010-09-17 17:31:01 +00005194 const int
5195 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005196
cristye7cc7cf2010-09-21 13:26:47 +00005197 assert(image != (Image *) NULL);
5198 assert(image->signature == MagickSignature);
5199 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005200 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005201 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005202 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005203 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5204 exception));
cristy3ed852e2009-09-05 21:47:34 +00005205}
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 s %
5213% %
5214% %
5215% %
5216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5217%
5218% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5219% The method returns MagickTrue if the pixel region is flushed, otherwise
5220% MagickFalse.
5221%
5222% The format of the SyncAuthenticPixels() method is:
5223%
5224% MagickBooleanType SyncAuthenticPixels(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*/
5234MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5235 ExceptionInfo *exception)
5236{
5237 CacheInfo
5238 *cache_info;
5239
cristy2036f5c2010-09-19 21:18:17 +00005240 const int
5241 id = GetOpenMPThreadId();
5242
cristy3ed852e2009-09-05 21:47:34 +00005243 assert(image != (Image *) NULL);
5244 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005245 assert(image->cache != (Cache) NULL);
5246 cache_info=(CacheInfo *) image->cache;
5247 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005248 if (cache_info->methods.sync_authentic_pixels_handler !=
5249 (SyncAuthenticPixelsHandler) NULL)
5250 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005251 assert(id < (int) cache_info->number_threads);
5252 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5253 exception));
cristy3ed852e2009-09-05 21:47:34 +00005254}
5255
5256/*
5257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5258% %
5259% %
5260% %
5261+ W r i t e P i x e l C a c h e I n d e x e s %
5262% %
5263% %
5264% %
5265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5266%
5267% WritePixelCacheIndexes() writes the colormap indexes to the specified
5268% region of the pixel cache.
5269%
5270% The format of the WritePixelCacheIndexes() method is:
5271%
5272% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5273% NexusInfo *nexus_info,ExceptionInfo *exception)
5274%
5275% A description of each parameter follows:
5276%
5277% o cache_info: the pixel cache.
5278%
5279% o nexus_info: the cache nexus to write the colormap indexes.
5280%
5281% o exception: return any errors or warnings in this structure.
5282%
5283*/
5284static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5285 NexusInfo *nexus_info,ExceptionInfo *exception)
5286{
5287 MagickOffsetType
5288 count,
5289 offset;
5290
5291 MagickSizeType
5292 length,
5293 number_pixels;
5294
5295 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005296 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005297
cristybb503372010-05-27 20:51:26 +00005298 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005299 y;
5300
cristybb503372010-05-27 20:51:26 +00005301 size_t
cristy3ed852e2009-09-05 21:47:34 +00005302 rows;
5303
cristy3ed852e2009-09-05 21:47:34 +00005304 if (cache_info->active_index_channel == MagickFalse)
5305 return(MagickFalse);
5306 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5307 return(MagickTrue);
5308 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5309 nexus_info->region.x;
5310 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5311 rows=nexus_info->region.height;
5312 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005313 p=nexus_info->indexes;
5314 switch (cache_info->type)
5315 {
5316 case MemoryCache:
5317 case MapCache:
5318 {
5319 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005320 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005321
5322 /*
5323 Write indexes to memory.
5324 */
cristydd341db2010-03-04 19:06:38 +00005325 if ((cache_info->columns == nexus_info->region.width) &&
5326 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5327 {
5328 length=number_pixels;
5329 rows=1UL;
5330 }
cristy3ed852e2009-09-05 21:47:34 +00005331 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005332 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005333 {
cristy8f036fe2010-09-18 02:02:00 +00005334 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005335 p+=nexus_info->region.width;
5336 q+=cache_info->columns;
5337 }
5338 break;
5339 }
5340 case DiskCache:
5341 {
5342 /*
5343 Write indexes to disk.
5344 */
5345 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5346 {
5347 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5348 cache_info->cache_filename);
5349 return(MagickFalse);
5350 }
cristydd341db2010-03-04 19:06:38 +00005351 if ((cache_info->columns == nexus_info->region.width) &&
5352 (number_pixels < MagickMaxBufferExtent))
5353 {
5354 length=number_pixels;
5355 rows=1UL;
5356 }
cristy3ed852e2009-09-05 21:47:34 +00005357 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005358 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005359 {
5360 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5361 sizeof(PixelPacket)+offset*sizeof(*p),length,
5362 (const unsigned char *) p);
5363 if ((MagickSizeType) count < length)
5364 break;
5365 p+=nexus_info->region.width;
5366 offset+=cache_info->columns;
5367 }
cristybb503372010-05-27 20:51:26 +00005368 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005369 {
5370 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5371 cache_info->cache_filename);
5372 return(MagickFalse);
5373 }
5374 break;
5375 }
5376 default:
5377 break;
5378 }
5379 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005380 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005381 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005382 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005383 nexus_info->region.width,(double) nexus_info->region.height,(double)
5384 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005385 return(MagickTrue);
5386}
5387
5388/*
5389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5390% %
5391% %
5392% %
5393+ W r i t e C a c h e P i x e l s %
5394% %
5395% %
5396% %
5397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5398%
5399% WritePixelCachePixels() writes image pixels to the specified region of the
5400% pixel cache.
5401%
5402% The format of the WritePixelCachePixels() method is:
5403%
5404% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5405% NexusInfo *nexus_info,ExceptionInfo *exception)
5406%
5407% A description of each parameter follows:
5408%
5409% o cache_info: the pixel cache.
5410%
5411% o nexus_info: the cache nexus to write the pixels.
5412%
5413% o exception: return any errors or warnings in this structure.
5414%
5415*/
5416static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5417 NexusInfo *nexus_info,ExceptionInfo *exception)
5418{
5419 MagickOffsetType
5420 count,
5421 offset;
5422
5423 MagickSizeType
5424 length,
5425 number_pixels;
5426
cristy3ed852e2009-09-05 21:47:34 +00005427 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005428 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005429
cristybb503372010-05-27 20:51:26 +00005430 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005431 y;
5432
cristybb503372010-05-27 20:51:26 +00005433 size_t
cristy3ed852e2009-09-05 21:47:34 +00005434 rows;
5435
cristy3ed852e2009-09-05 21:47:34 +00005436 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5437 return(MagickTrue);
5438 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5439 nexus_info->region.x;
5440 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5441 rows=nexus_info->region.height;
5442 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005443 p=nexus_info->pixels;
5444 switch (cache_info->type)
5445 {
5446 case MemoryCache:
5447 case MapCache:
5448 {
5449 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005450 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005451
5452 /*
5453 Write pixels to memory.
5454 */
cristydd341db2010-03-04 19:06:38 +00005455 if ((cache_info->columns == nexus_info->region.width) &&
5456 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5457 {
5458 length=number_pixels;
5459 rows=1UL;
5460 }
cristy3ed852e2009-09-05 21:47:34 +00005461 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005462 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005463 {
cristy8f036fe2010-09-18 02:02:00 +00005464 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005465 p+=nexus_info->region.width;
5466 q+=cache_info->columns;
5467 }
5468 break;
5469 }
5470 case DiskCache:
5471 {
5472 /*
5473 Write pixels to disk.
5474 */
5475 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5476 {
5477 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5478 cache_info->cache_filename);
5479 return(MagickFalse);
5480 }
cristydd341db2010-03-04 19:06:38 +00005481 if ((cache_info->columns == nexus_info->region.width) &&
5482 (number_pixels < MagickMaxBufferExtent))
5483 {
5484 length=number_pixels;
5485 rows=1UL;
5486 }
cristybb503372010-05-27 20:51:26 +00005487 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005488 {
5489 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5490 sizeof(*p),length,(const unsigned char *) p);
5491 if ((MagickSizeType) count < length)
5492 break;
5493 p+=nexus_info->region.width;
5494 offset+=cache_info->columns;
5495 }
cristybb503372010-05-27 20:51:26 +00005496 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005497 {
5498 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5499 cache_info->cache_filename);
5500 return(MagickFalse);
5501 }
5502 break;
5503 }
5504 default:
5505 break;
5506 }
5507 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005508 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005509 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005510 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005511 nexus_info->region.width,(double) nexus_info->region.height,(double)
5512 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005513 return(MagickTrue);
5514}