blob: 6f4b9d7a95ea719bb67a7a80468ce86157be0559 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
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
cristy73bd4a52010-10-05 11:24:23 +0000188 cache_info=(CacheInfo *) AcquireMagickMemory(sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
cristy0d267172011-04-25 20:13:48 +0000195 cache_info->channels=4;
cristy3ed852e2009-09-05 21:47:34 +0000196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristy2cd7a752010-08-23 00:48:54 +0000250MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristyb41ee102010-10-04 16:46:15 +0000258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
cristy6a924af2010-09-23 14:02:54 +0000264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
301MagickExport const void *AcquirePixelCachePixels(const Image *image,
302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
339MagickExport MagickBooleanType CacheComponentGenesis(void)
340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
363MagickExport void CacheComponentTerminus(void)
364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
387% mask. The method returns MagickTrue if the pixel region is clipped,
388% otherwise MagickFalse.
389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
417 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000418 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000419
420 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000421 *restrict nexus_indexes,
422 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristy3ed852e2009-09-05 21:47:34 +0000424 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000425 *restrict p,
426 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000427
cristye076a6e2010-08-15 19:59:43 +0000428 register ssize_t
429 i;
430
cristy3ed852e2009-09-05 21:47:34 +0000431 /*
432 Apply clip mask.
433 */
434 if (image->debug != MagickFalse)
435 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
436 if (image->clip_mask == (Image *) NULL)
437 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000438 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000439 if (cache_info == (Cache) NULL)
440 return(MagickFalse);
441 image_nexus=AcquirePixelCacheNexus(1);
442 clip_nexus=AcquirePixelCacheNexus(1);
443 if ((image_nexus == (NexusInfo **) NULL) ||
444 (clip_nexus == (NexusInfo **) NULL))
445 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
446 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
447 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
448 exception);
cristy2036f5c2010-09-19 21:18:17 +0000449 indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +0000450 q=nexus_info->pixels;
451 nexus_indexes=nexus_info->indexes;
452 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
453 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
454 nexus_info->region.height,clip_nexus[0],exception);
455 number_pixels=(MagickSizeType) nexus_info->region.width*
456 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000457 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000458 {
459 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
460 break;
461 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
462 {
cristyef618312011-06-25 12:26:44 +0000463 SetPixelRed(q,GetPixelRed(p));
464 SetPixelGreen(q,GetPixelGreen(p));
465 SetPixelBlue(q,GetPixelBlue(p));
466 SetPixelOpacity(q,GetPixelOpacity(p));
cristy3ed852e2009-09-05 21:47:34 +0000467 if (cache_info->active_index_channel != MagickFalse)
cristyef618312011-06-25 12:26:44 +0000468 SetPixelIndex(nexus_indexes+i,GetPixelIndex(
cristyc8d25bc2011-04-29 02:19:30 +0000469 indexes+i));
cristy3ed852e2009-09-05 21:47:34 +0000470 }
471 p++;
472 q++;
473 r++;
474 }
475 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
476 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000477 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000478 return(MagickFalse);
479 return(MagickTrue);
480}
481
482/*
483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484% %
485% %
486% %
487+ C l o n e P i x e l C a c h e %
488% %
489% %
490% %
491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492%
493% ClonePixelCache() clones a pixel cache.
494%
495% The format of the ClonePixelCache() method is:
496%
497% Cache ClonePixelCache(const Cache cache)
498%
499% A description of each parameter follows:
500%
501% o cache: the pixel cache.
502%
503*/
504MagickExport Cache ClonePixelCache(const Cache cache)
505{
506 CacheInfo
507 *clone_info;
508
509 const CacheInfo
510 *cache_info;
511
512 assert(cache != (const Cache) NULL);
513 cache_info=(const CacheInfo *) cache;
514 assert(cache_info->signature == MagickSignature);
515 if (cache_info->debug != MagickFalse)
516 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
517 cache_info->filename);
518 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
519 if (clone_info == (Cache) NULL)
520 return((Cache) NULL);
521 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
522 return((Cache ) clone_info);
523}
524
525/*
526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
527% %
528% %
529% %
cristy60c44a82009-10-07 00:58:49 +0000530+ 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 +0000531% %
532% %
533% %
534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
535% ClonePixelCachePixels() clones the source pixel cache to the destination
536% cache.
537%
538% The format of the ClonePixelCachePixels() method is:
539%
540% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
541% CacheInfo *source_info,ExceptionInfo *exception)
542%
543% A description of each parameter follows:
544%
545% o cache_info: the pixel cache.
546%
547% o source_info: the source pixel cache.
548%
549% o exception: return any errors or warnings in this structure.
550%
551*/
552
553static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
554{
555 int
556 status;
557
cristy5ee247a2010-02-12 15:42:34 +0000558 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000559 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000560 if (cache_info->file != -1)
561 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000562 cache_info->file=(-1);
563 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000564 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000565 return(status == -1 ? MagickFalse : MagickTrue);
566}
567
568static void LimitPixelCacheDescriptors(void)
569{
570 register CacheInfo
571 *p,
572 *q;
573
574 /*
575 Limit # of open file descriptors.
576 */
577 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
578 return;
cristyf84a1932010-01-03 18:00:18 +0000579 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000580 if (cache_resources == (SplayTreeInfo *) NULL)
581 {
cristyf84a1932010-01-03 18:00:18 +0000582 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000583 return;
584 }
585 ResetSplayTreeIterator(cache_resources);
586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
587 while (p != (CacheInfo *) NULL)
588 {
589 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000590 break;
cristy3ed852e2009-09-05 21:47:34 +0000591 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
592 }
593 for (q=p; p != (CacheInfo *) NULL; )
594 {
595 if ((p->type == DiskCache) && (p->file != -1) &&
596 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000597 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000598 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
599 }
600 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000601 {
602 /*
603 Close least recently used cache.
604 */
605 (void) close(q->file);
606 q->file=(-1);
607 }
cristyf84a1932010-01-03 18:00:18 +0000608 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000609}
610
611static inline MagickSizeType MagickMax(const MagickSizeType x,
612 const MagickSizeType y)
613{
614 if (x > y)
615 return(x);
616 return(y);
617}
618
619static inline MagickSizeType MagickMin(const MagickSizeType x,
620 const MagickSizeType y)
621{
622 if (x < y)
623 return(x);
624 return(y);
625}
626
627static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
628 const MapMode mode)
629{
630 int
631 file;
632
633 /*
634 Open pixel cache on disk.
635 */
cristyf84a1932010-01-03 18:00:18 +0000636 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000637 if (cache_info->file != -1)
638 {
cristyf84a1932010-01-03 18:00:18 +0000639 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000640 return(MagickTrue); /* cache already open */
641 }
642 LimitPixelCacheDescriptors();
643 if (*cache_info->cache_filename == '\0')
644 file=AcquireUniqueFileResource(cache_info->cache_filename);
645 else
646 switch (mode)
647 {
648 case ReadMode:
649 {
650 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
651 break;
652 }
653 case WriteMode:
654 {
655 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
656 O_EXCL,S_MODE);
657 if (file == -1)
658 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
659 break;
660 }
661 case IOMode:
662 default:
663 {
664 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
665 O_EXCL,S_MODE);
666 if (file == -1)
667 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
668 break;
669 }
670 }
671 if (file == -1)
672 {
cristyf84a1932010-01-03 18:00:18 +0000673 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000674 return(MagickFalse);
675 }
676 (void) AcquireMagickResource(FileResource,1);
677 cache_info->file=file;
678 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000679 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000680 return(MagickTrue);
681}
682
683static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
684 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000685 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000686{
687 register MagickOffsetType
688 i;
689
690 ssize_t
691 count;
692
cristy08a88202010-03-04 19:18:05 +0000693 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000694#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000695 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000696 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000697 {
cristyf84a1932010-01-03 18:00:18 +0000698 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000699 return((MagickOffsetType) -1);
700 }
701#endif
702 count=0;
703 for (i=0; i < (MagickOffsetType) length; i+=count)
704 {
705#if !defined(MAGICKCORE_HAVE_PREAD)
706 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
707 (MagickSizeType) SSIZE_MAX));
708#else
709 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000710 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000711#endif
712 if (count > 0)
713 continue;
714 count=0;
715 if (errno != EINTR)
716 {
717 i=(-1);
718 break;
719 }
720 }
721#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000722 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000723#endif
724 return(i);
725}
726
727static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
728 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000729 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000730{
731 register MagickOffsetType
732 i;
733
734 ssize_t
735 count;
736
cristy08a88202010-03-04 19:18:05 +0000737 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000738#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000739 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000740 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000741 {
cristyf84a1932010-01-03 18:00:18 +0000742 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000743 return((MagickOffsetType) -1);
744 }
745#endif
746 count=0;
747 for (i=0; i < (MagickOffsetType) length; i+=count)
748 {
749#if !defined(MAGICKCORE_HAVE_PWRITE)
750 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
751 (MagickSizeType) SSIZE_MAX));
752#else
753 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000754 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000755#endif
756 if (count > 0)
757 continue;
758 count=0;
759 if (errno != EINTR)
760 {
761 i=(-1);
762 break;
763 }
764 }
765#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000766 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000767#endif
768 return(i);
769}
770
771static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
772 CacheInfo *cache_info,ExceptionInfo *exception)
773{
774 MagickOffsetType
775 count,
776 offset,
777 source_offset;
778
779 MagickSizeType
780 length;
781
cristy3ed852e2009-09-05 21:47:34 +0000782 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000783 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000784
cristye076a6e2010-08-15 19:59:43 +0000785 register ssize_t
786 y;
787
cristybb503372010-05-27 20:51:26 +0000788 size_t
cristy3ed852e2009-09-05 21:47:34 +0000789 columns,
790 rows;
791
792 if (cache_info->debug != MagickFalse)
793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
794 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
795 {
796 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
797 clone_info->cache_filename);
798 return(MagickFalse);
799 }
800 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
801 {
802 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
803 cache_info->cache_filename);
804 return(MagickFalse);
805 }
cristybb503372010-05-27 20:51:26 +0000806 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
807 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000808 if ((clone_info->active_index_channel != MagickFalse) &&
809 (cache_info->active_index_channel != MagickFalse))
810 {
811 register IndexPacket
812 *indexes;
813
814 /*
815 Clone cache indexes.
816 */
817 length=MagickMax(clone_info->columns,cache_info->columns)*
818 sizeof(*indexes);
819 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
820 if (indexes == (IndexPacket *) NULL)
821 {
822 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
823 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
824 return(MagickFalse);
825 }
826 (void) ResetMagickMemory(indexes,0,(size_t) length);
827 length=columns*sizeof(*indexes);
828 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
cristye3fe0242011-02-19 14:37:09 +0000829 sizeof(*pixels);
cristy3ed852e2009-09-05 21:47:34 +0000830 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
cristye3fe0242011-02-19 14:37:09 +0000831 sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000832 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000833 {
cristy3ed852e2009-09-05 21:47:34 +0000834 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
835 length,(unsigned char *) indexes);
836 if ((MagickSizeType) count != length)
837 break;
cristy3ed852e2009-09-05 21:47:34 +0000838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
841 break;
cristye3fe0242011-02-19 14:37:09 +0000842 source_offset+=cache_info->columns*sizeof(*indexes);
843 offset+=clone_info->columns*sizeof(*indexes);
cristy3ed852e2009-09-05 21:47:34 +0000844 }
cristybb503372010-05-27 20:51:26 +0000845 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000846 {
847 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
848 ThrowFileException(exception,CacheError,"UnableToCloneCache",
849 cache_info->cache_filename);
850 return(MagickFalse);
851 }
852 if (clone_info->columns > cache_info->columns)
853 {
854 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
855 (void) ResetMagickMemory(indexes,0,(size_t) length);
856 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
cristye3fe0242011-02-19 14:37:09 +0000857 sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000858 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000859 {
cristy3ed852e2009-09-05 21:47:34 +0000860 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
861 length,(unsigned char *) indexes);
862 if ((MagickSizeType) count != length)
863 break;
cristye3fe0242011-02-19 14:37:09 +0000864 offset+=clone_info->columns*sizeof(*indexes);
cristy3ed852e2009-09-05 21:47:34 +0000865 }
cristybb503372010-05-27 20:51:26 +0000866 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000867 {
868 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
869 ThrowFileException(exception,CacheError,"UnableToCloneCache",
870 cache_info->cache_filename);
871 return(MagickFalse);
872 }
873 }
874 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
875 }
876 /*
877 Clone cache pixels.
878 */
879 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
880 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
881 if (pixels == (PixelPacket *) NULL)
882 {
883 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
884 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
885 return(MagickFalse);
886 }
887 (void) ResetMagickMemory(pixels,0,(size_t) length);
888 length=columns*sizeof(*pixels);
cristye3fe0242011-02-19 14:37:09 +0000889 source_offset=0;
890 offset=0;
cristybb503372010-05-27 20:51:26 +0000891 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000892 {
cristy3ed852e2009-09-05 21:47:34 +0000893 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
894 length,(unsigned char *) pixels);
895 if ((MagickSizeType) count != length)
896 break;
cristy3ed852e2009-09-05 21:47:34 +0000897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
900 break;
cristye3fe0242011-02-19 14:37:09 +0000901 source_offset+=cache_info->columns*sizeof(*pixels);
902 offset+=clone_info->columns*sizeof(*pixels);
cristy3ed852e2009-09-05 21:47:34 +0000903 }
cristybb503372010-05-27 20:51:26 +0000904 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000905 {
906 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
907 ThrowFileException(exception,CacheError,"UnableToCloneCache",
908 cache_info->cache_filename);
909 return(MagickFalse);
910 }
911 if (clone_info->columns > cache_info->columns)
912 {
cristy3ed852e2009-09-05 21:47:34 +0000913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristye3fe0242011-02-19 14:37:09 +0000915 offset=(MagickOffsetType) columns*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000916 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000917 {
cristy3ed852e2009-09-05 21:47:34 +0000918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
921 break;
cristye3fe0242011-02-19 14:37:09 +0000922 offset+=clone_info->columns*sizeof(*pixels);
cristy3ed852e2009-09-05 21:47:34 +0000923 }
cristybb503372010-05-27 20:51:26 +0000924 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000925 {
926 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
927 ThrowFileException(exception,CacheError,"UnableToCloneCache",
928 cache_info->cache_filename);
929 return(MagickFalse);
930 }
931 }
932 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
933 return(MagickTrue);
934}
935
936static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
937 CacheInfo *cache_info,ExceptionInfo *exception)
938{
939 MagickOffsetType
940 count,
941 offset;
942
943 MagickSizeType
944 length;
945
cristy3ed852e2009-09-05 21:47:34 +0000946 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000947 *restrict pixels,
948 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000949
cristye076a6e2010-08-15 19:59:43 +0000950 register ssize_t
951 y;
952
cristybb503372010-05-27 20:51:26 +0000953 size_t
cristy3ed852e2009-09-05 21:47:34 +0000954 columns,
955 rows;
956
957 if (cache_info->debug != MagickFalse)
958 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
959 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
960 {
961 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
962 cache_info->cache_filename);
963 return(MagickFalse);
964 }
cristybb503372010-05-27 20:51:26 +0000965 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
966 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000967 if ((clone_info->active_index_channel != MagickFalse) &&
968 (cache_info->active_index_channel != MagickFalse))
969 {
970 register IndexPacket
971 *indexes,
972 *q;
973
974 /*
975 Clone cache indexes.
976 */
977 length=MagickMax(clone_info->columns,cache_info->columns)*
978 sizeof(*indexes);
979 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
980 if (indexes == (IndexPacket *) NULL)
981 {
982 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
983 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
984 return(MagickFalse);
985 }
986 (void) ResetMagickMemory(indexes,0,(size_t) length);
987 length=columns*sizeof(IndexPacket);
988 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
cristye3fe0242011-02-19 14:37:09 +0000989 sizeof(*pixels);
990 q=clone_info->indexes;
cristybb503372010-05-27 20:51:26 +0000991 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000992 {
cristy3ed852e2009-09-05 21:47:34 +0000993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
996 break;
cristy8f036fe2010-09-18 02:02:00 +0000997 (void) memcpy(q,indexes,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000998 if ((MagickSizeType) count != length)
999 break;
cristye3fe0242011-02-19 14:37:09 +00001000 offset+=cache_info->columns*sizeof(*indexes);
1001 q+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001002 }
cristybb503372010-05-27 20:51:26 +00001003 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001004 {
1005 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1006 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1007 cache_info->cache_filename);
1008 return(MagickFalse);
1009 }
1010 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1011 }
1012 /*
1013 Clone cache pixels.
1014 */
1015 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1016 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1017 if (pixels == (PixelPacket *) NULL)
1018 {
1019 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1020 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1021 return(MagickFalse);
1022 }
1023 (void) ResetMagickMemory(pixels,0,(size_t) length);
1024 length=columns*sizeof(*pixels);
cristye3fe0242011-02-19 14:37:09 +00001025 offset=0;
1026 q=clone_info->pixels;
cristybb503372010-05-27 20:51:26 +00001027 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001028 {
cristy3ed852e2009-09-05 21:47:34 +00001029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1032 break;
cristy8f036fe2010-09-18 02:02:00 +00001033 (void) memcpy(q,pixels,(size_t) length);
cristye3fe0242011-02-19 14:37:09 +00001034 offset+=cache_info->columns*sizeof(*pixels);
1035 q+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001036 }
cristybb503372010-05-27 20:51:26 +00001037 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001038 {
1039 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1040 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1041 cache_info->cache_filename);
1042 return(MagickFalse);
1043 }
1044 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1045 return(MagickTrue);
1046}
1047
1048static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1049 CacheInfo *cache_info,ExceptionInfo *exception)
1050{
1051 MagickOffsetType
1052 count,
1053 offset;
1054
1055 MagickSizeType
1056 length;
1057
cristy3ed852e2009-09-05 21:47:34 +00001058 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001059 *restrict p,
1060 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001061
cristye076a6e2010-08-15 19:59:43 +00001062 register ssize_t
1063 y;
1064
cristybb503372010-05-27 20:51:26 +00001065 size_t
cristy3ed852e2009-09-05 21:47:34 +00001066 columns,
1067 rows;
1068
1069 if (cache_info->debug != MagickFalse)
1070 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1071 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1072 {
1073 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1074 clone_info->cache_filename);
1075 return(MagickFalse);
1076 }
cristybb503372010-05-27 20:51:26 +00001077 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1078 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001079 if ((clone_info->active_index_channel != MagickFalse) &&
1080 (cache_info->active_index_channel != MagickFalse))
1081 {
1082 register IndexPacket
1083 *p,
1084 *indexes;
1085
1086 /*
1087 Clone cache indexes.
1088 */
1089 length=MagickMax(clone_info->columns,cache_info->columns)*
1090 sizeof(*indexes);
1091 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1092 if (indexes == (IndexPacket *) NULL)
1093 {
1094 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1095 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1096 return(MagickFalse);
1097 }
1098 (void) ResetMagickMemory(indexes,0,(size_t) length);
1099 length=columns*sizeof(*indexes);
cristye3fe0242011-02-19 14:37:09 +00001100 p=cache_info->indexes;
cristy3ed852e2009-09-05 21:47:34 +00001101 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
cristye3fe0242011-02-19 14:37:09 +00001102 sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001103 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001104 {
cristy8f036fe2010-09-18 02:02:00 +00001105 (void) memcpy(indexes,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001106 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1107 (unsigned char *) indexes);
1108 if ((MagickSizeType) count != length)
1109 break;
cristye3fe0242011-02-19 14:37:09 +00001110 p+=cache_info->columns;
1111 offset+=clone_info->columns*sizeof(*indexes);
cristy3ed852e2009-09-05 21:47:34 +00001112 }
cristybb503372010-05-27 20:51:26 +00001113 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001114 {
1115 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1116 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1117 cache_info->cache_filename);
1118 return(MagickFalse);
1119 }
1120 if (clone_info->columns > cache_info->columns)
1121 {
1122 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1123 (void) ResetMagickMemory(indexes,0,(size_t) length);
1124 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
cristye3fe0242011-02-19 14:37:09 +00001125 sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001126 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001127 {
cristy3ed852e2009-09-05 21:47:34 +00001128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1131 break;
cristye3fe0242011-02-19 14:37:09 +00001132 offset+=clone_info->columns*sizeof(*indexes);
cristy3ed852e2009-09-05 21:47:34 +00001133 }
cristybb503372010-05-27 20:51:26 +00001134 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001135 {
1136 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1137 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1138 cache_info->cache_filename);
1139 return(MagickFalse);
1140 }
1141 }
1142 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1143 }
1144 /*
1145 Clone cache pixels.
1146 */
1147 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1148 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1149 if (pixels == (PixelPacket *) NULL)
1150 {
1151 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1152 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1153 return(MagickFalse);
1154 }
1155 (void) ResetMagickMemory(pixels,0,(size_t) length);
1156 length=columns*sizeof(*pixels);
cristye3fe0242011-02-19 14:37:09 +00001157 p=cache_info->pixels;
1158 offset=0;
cristybb503372010-05-27 20:51:26 +00001159 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001160 {
cristy8f036fe2010-09-18 02:02:00 +00001161 (void) memcpy(pixels,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001162 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1163 (unsigned char *) pixels);
1164 if ((MagickSizeType) count != length)
1165 break;
cristye3fe0242011-02-19 14:37:09 +00001166 p+=cache_info->columns;
1167 offset+=clone_info->columns*sizeof(*pixels);
cristy3ed852e2009-09-05 21:47:34 +00001168 }
cristybb503372010-05-27 20:51:26 +00001169 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001170 {
1171 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1172 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1173 cache_info->cache_filename);
1174 return(MagickFalse);
1175 }
1176 if (clone_info->columns > cache_info->columns)
1177 {
cristy3ed852e2009-09-05 21:47:34 +00001178 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1179 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristye3fe0242011-02-19 14:37:09 +00001180 offset=(MagickOffsetType) columns*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001181 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001182 {
cristy3ed852e2009-09-05 21:47:34 +00001183 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1184 (unsigned char *) pixels);
1185 if ((MagickSizeType) count != length)
1186 break;
cristye3fe0242011-02-19 14:37:09 +00001187 offset+=clone_info->columns*sizeof(*pixels);
cristy3ed852e2009-09-05 21:47:34 +00001188 }
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 {
cristye3fe0242011-02-19 14:37:09 +00001235 source_indexes=cache_info->indexes;
1236 indexes=clone_info->indexes;
cristybb503372010-05-27 20:51:26 +00001237 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001238 {
cristy8f036fe2010-09-18 02:02:00 +00001239 (void) memcpy(indexes,source_indexes,length);
cristye3fe0242011-02-19 14:37:09 +00001240 source_indexes+=cache_info->columns;
1241 indexes+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001242 }
1243 if (clone_info->columns > cache_info->columns)
1244 {
cristye3fe0242011-02-19 14:37:09 +00001245 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1246 indexes=clone_info->indexes+cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001247 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001248 {
cristy3ed852e2009-09-05 21:47:34 +00001249 (void) ResetMagickMemory(indexes,0,length);
cristye3fe0242011-02-19 14:37:09 +00001250 indexes+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001251 }
1252 }
1253 }
1254 }
1255 /*
1256 Clone cache pixels.
1257 */
1258 length=columns*sizeof(*pixels);
1259 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001260 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001261 else
1262 {
cristye3fe0242011-02-19 14:37:09 +00001263 source_pixels=cache_info->pixels;
1264 pixels=clone_info->pixels;
cristybb503372010-05-27 20:51:26 +00001265 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001266 {
cristy8f036fe2010-09-18 02:02:00 +00001267 (void) memcpy(pixels,source_pixels,length);
cristye3fe0242011-02-19 14:37:09 +00001268 source_pixels+=cache_info->columns;
1269 pixels+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001270 }
1271 if (clone_info->columns > cache_info->columns)
1272 {
1273 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
cristye3fe0242011-02-19 14:37:09 +00001274 pixels=clone_info->pixels+cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001275 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001276 {
cristy3ed852e2009-09-05 21:47:34 +00001277 (void) ResetMagickMemory(pixels,0,length);
cristye3fe0242011-02-19 14:37:09 +00001278 pixels+=clone_info->columns;
cristy3ed852e2009-09-05 21:47:34 +00001279 }
1280 }
1281 }
1282 return(MagickTrue);
1283}
1284
1285static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1286 CacheInfo *cache_info,ExceptionInfo *exception)
1287{
cristy5a7fbfb2010-11-06 16:10:59 +00001288 if (cache_info->type == PingCache)
1289 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001290 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1291 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1292 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1293 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1294 if (cache_info->type == DiskCache)
1295 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1296 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1297}
1298
1299/*
1300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301% %
1302% %
1303% %
1304+ C l o n e P i x e l C a c h e M e t h o d s %
1305% %
1306% %
1307% %
1308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309%
1310% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1311% another.
1312%
1313% The format of the ClonePixelCacheMethods() method is:
1314%
1315% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1316%
1317% A description of each parameter follows:
1318%
1319% o clone: Specifies a pointer to a Cache structure.
1320%
1321% o cache: the pixel cache.
1322%
1323*/
1324MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1325{
1326 CacheInfo
1327 *cache_info,
1328 *source_info;
1329
1330 assert(clone != (Cache) NULL);
1331 source_info=(CacheInfo *) clone;
1332 assert(source_info->signature == MagickSignature);
1333 if (source_info->debug != MagickFalse)
1334 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1335 source_info->filename);
1336 assert(cache != (Cache) NULL);
1337 cache_info=(CacheInfo *) cache;
1338 assert(cache_info->signature == MagickSignature);
1339 source_info->methods=cache_info->methods;
1340}
1341
1342/*
1343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1344% %
1345% %
1346% %
1347+ D e s t r o y I m a g e P i x e l C a c h e %
1348% %
1349% %
1350% %
1351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1352%
1353% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1354%
1355% The format of the DestroyImagePixelCache() method is:
1356%
1357% void DestroyImagePixelCache(Image *image)
1358%
1359% A description of each parameter follows:
1360%
1361% o image: the image.
1362%
1363*/
1364static void DestroyImagePixelCache(Image *image)
1365{
1366 assert(image != (Image *) NULL);
1367 assert(image->signature == MagickSignature);
1368 if (image->debug != MagickFalse)
1369 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1370 if (image->cache == (void *) NULL)
1371 return;
1372 image->cache=DestroyPixelCache(image->cache);
1373}
1374
1375/*
1376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377% %
1378% %
1379% %
1380+ D e s t r o y I m a g e P i x e l s %
1381% %
1382% %
1383% %
1384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385%
1386% DestroyImagePixels() deallocates memory associated with the pixel cache.
1387%
1388% The format of the DestroyImagePixels() method is:
1389%
1390% void DestroyImagePixels(Image *image)
1391%
1392% A description of each parameter follows:
1393%
1394% o image: the image.
1395%
1396*/
1397MagickExport void DestroyImagePixels(Image *image)
1398{
1399 CacheInfo
1400 *cache_info;
1401
1402 assert(image != (const Image *) NULL);
1403 assert(image->signature == MagickSignature);
1404 if (image->debug != MagickFalse)
1405 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1406 assert(image->cache != (Cache) NULL);
1407 cache_info=(CacheInfo *) image->cache;
1408 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001409 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1410 {
1411 cache_info->methods.destroy_pixel_handler(image);
1412 return;
1413 }
cristy2036f5c2010-09-19 21:18:17 +00001414 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001415}
1416
1417/*
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419% %
1420% %
1421% %
1422+ D e s t r o y P i x e l C a c h e %
1423% %
1424% %
1425% %
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427%
1428% DestroyPixelCache() deallocates memory associated with the pixel cache.
1429%
1430% The format of the DestroyPixelCache() method is:
1431%
1432% Cache DestroyPixelCache(Cache cache)
1433%
1434% A description of each parameter follows:
1435%
1436% o cache: the pixel cache.
1437%
1438*/
1439
1440static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1441{
1442 switch (cache_info->type)
1443 {
1444 case MemoryCache:
1445 {
1446 if (cache_info->mapped == MagickFalse)
1447 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1448 cache_info->pixels);
1449 else
1450 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1451 (size_t) cache_info->length);
1452 RelinquishMagickResource(MemoryResource,cache_info->length);
1453 break;
1454 }
1455 case MapCache:
1456 {
1457 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1458 cache_info->length);
1459 RelinquishMagickResource(MapResource,cache_info->length);
1460 }
1461 case DiskCache:
1462 {
1463 if (cache_info->file != -1)
1464 (void) ClosePixelCacheOnDisk(cache_info);
1465 RelinquishMagickResource(DiskResource,cache_info->length);
1466 break;
1467 }
1468 default:
1469 break;
1470 }
1471 cache_info->type=UndefinedCache;
1472 cache_info->mapped=MagickFalse;
1473 cache_info->indexes=(IndexPacket *) NULL;
1474}
1475
1476MagickExport Cache DestroyPixelCache(Cache cache)
1477{
1478 CacheInfo
1479 *cache_info;
1480
cristy3ed852e2009-09-05 21:47:34 +00001481 assert(cache != (Cache) NULL);
1482 cache_info=(CacheInfo *) cache;
1483 assert(cache_info->signature == MagickSignature);
1484 if (cache_info->debug != MagickFalse)
1485 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1486 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001487 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001488 cache_info->reference_count--;
1489 if (cache_info->reference_count != 0)
1490 {
cristyf84a1932010-01-03 18:00:18 +00001491 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001492 return((Cache) NULL);
1493 }
cristyf84a1932010-01-03 18:00:18 +00001494 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001495 if (cache_resources != (SplayTreeInfo *) NULL)
1496 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001497 if (cache_info->debug != MagickFalse)
1498 {
1499 char
1500 message[MaxTextExtent];
1501
cristyb51dff52011-05-19 16:55:47 +00001502 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001503 cache_info->filename);
1504 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1505 }
cristyc2e1bdd2009-09-10 23:43:34 +00001506 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1507 (cache_info->type != DiskCache)))
1508 RelinquishPixelCachePixels(cache_info);
1509 else
1510 {
1511 RelinquishPixelCachePixels(cache_info);
1512 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1513 }
cristy3ed852e2009-09-05 21:47:34 +00001514 *cache_info->cache_filename='\0';
1515 if (cache_info->nexus_info != (NexusInfo **) NULL)
1516 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1517 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001518 if (cache_info->random_info != (RandomInfo *) NULL)
1519 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001520 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1521 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1522 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1523 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001524 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001525 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001526 cache=(Cache) NULL;
1527 return(cache);
1528}
1529
1530/*
1531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532% %
1533% %
1534% %
1535+ D e s t r o y P i x e l C a c h e N e x u s %
1536% %
1537% %
1538% %
1539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540%
1541% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1542%
1543% The format of the DestroyPixelCacheNexus() method is:
1544%
1545% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001546% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001547%
1548% A description of each parameter follows:
1549%
1550% o nexus_info: the nexus to destroy.
1551%
1552% o number_threads: the number of nexus threads.
1553%
1554*/
1555
1556static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1557{
1558 if (nexus_info->mapped == MagickFalse)
1559 (void) RelinquishMagickMemory(nexus_info->cache);
1560 else
1561 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1562 nexus_info->cache=(PixelPacket *) NULL;
1563 nexus_info->pixels=(PixelPacket *) NULL;
1564 nexus_info->indexes=(IndexPacket *) NULL;
1565 nexus_info->length=0;
1566 nexus_info->mapped=MagickFalse;
1567}
1568
1569MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001570 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001571{
cristybb503372010-05-27 20:51:26 +00001572 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001573 i;
1574
1575 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001576 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001577 {
1578 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1579 RelinquishCacheNexusPixels(nexus_info[i]);
1580 nexus_info[i]->signature=(~MagickSignature);
1581 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1582 }
cristyb41ee102010-10-04 16:46:15 +00001583 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001584 return(nexus_info);
1585}
1586
1587/*
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589% %
1590% %
1591% %
cristy3ed852e2009-09-05 21:47:34 +00001592+ 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 %
1593% %
1594% %
1595% %
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597%
1598% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1599% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1600%
1601% The format of the GetAuthenticIndexesFromCache() method is:
1602%
1603% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1604%
1605% A description of each parameter follows:
1606%
1607% o image: the image.
1608%
1609*/
1610static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1611{
1612 CacheInfo
1613 *cache_info;
1614
cristy5c9e6f22010-09-17 17:31:01 +00001615 const int
1616 id = GetOpenMPThreadId();
1617
cristye7cc7cf2010-09-21 13:26:47 +00001618 assert(image != (const Image *) NULL);
1619 assert(image->signature == MagickSignature);
1620 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001621 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001622 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001623 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001624 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001625}
1626
1627/*
1628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629% %
1630% %
1631% %
1632% G e t A u t h e n t i c I n d e x Q u e u e %
1633% %
1634% %
1635% %
1636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637%
1638% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1639% indexes associated with the last call to QueueAuthenticPixels() or
1640% GetVirtualPixels(). NULL is returned if the black channel or colormap
1641% indexes are not available.
1642%
1643% The format of the GetAuthenticIndexQueue() method is:
1644%
1645% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1646%
1647% A description of each parameter follows:
1648%
1649% o image: the image.
1650%
1651*/
1652MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1653{
1654 CacheInfo
1655 *cache_info;
1656
cristy2036f5c2010-09-19 21:18:17 +00001657 const int
1658 id = GetOpenMPThreadId();
1659
cristy3ed852e2009-09-05 21:47:34 +00001660 assert(image != (const Image *) NULL);
1661 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001662 assert(image->cache != (Cache) NULL);
1663 cache_info=(CacheInfo *) image->cache;
1664 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001665 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001666 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001667 return(cache_info->methods.get_authentic_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001668 assert(id < (int) cache_info->number_threads);
1669 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001670}
1671
1672/*
1673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1674% %
1675% %
1676% %
1677+ 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 %
1678% %
1679% %
1680% %
1681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1682%
1683% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1684% disk pixel cache as defined by the geometry parameters. A pointer to the
1685% pixels is returned if the pixels are transferred, otherwise a NULL is
1686% returned.
1687%
1688% The format of the GetAuthenticPixelCacheNexus() method is:
1689%
cristybb503372010-05-27 20:51:26 +00001690% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1691% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001692% NexusInfo *nexus_info,ExceptionInfo *exception)
1693%
1694% A description of each parameter follows:
1695%
1696% o image: the image.
1697%
1698% o x,y,columns,rows: These values define the perimeter of a region of
1699% pixels.
1700%
1701% o nexus_info: the cache nexus to return.
1702%
1703% o exception: return any errors or warnings in this structure.
1704%
1705*/
1706
1707static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1708 NexusInfo *nexus_info)
1709{
1710 MagickOffsetType
1711 offset;
1712
cristy73724512010-04-12 14:43:14 +00001713 if (cache_info->type == PingCache)
1714 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001715 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1716 nexus_info->region.x;
cristy096bf2c2010-09-22 11:55:02 +00001717 return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
1718 MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001719}
1720
cristye076a6e2010-08-15 19:59:43 +00001721MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1722 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001723 NexusInfo *nexus_info,ExceptionInfo *exception)
1724{
1725 CacheInfo
1726 *cache_info;
1727
1728 PixelPacket
1729 *pixels;
1730
1731 /*
1732 Transfer pixels from the cache.
1733 */
1734 assert(image != (Image *) NULL);
1735 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001736 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1737 if (pixels == (PixelPacket *) NULL)
1738 return((PixelPacket *) NULL);
1739 cache_info=(CacheInfo *) image->cache;
1740 assert(cache_info->signature == MagickSignature);
1741 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1742 return(pixels);
1743 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1744 return((PixelPacket *) NULL);
1745 if (cache_info->active_index_channel != MagickFalse)
1746 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1747 return((PixelPacket *) NULL);
1748 return(pixels);
1749}
1750
1751/*
1752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1753% %
1754% %
1755% %
1756+ 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 %
1757% %
1758% %
1759% %
1760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761%
1762% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1763% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1764%
1765% The format of the GetAuthenticPixelsFromCache() method is:
1766%
1767% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1768%
1769% A description of each parameter follows:
1770%
1771% o image: the image.
1772%
1773*/
1774static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1775{
1776 CacheInfo
1777 *cache_info;
1778
cristy5c9e6f22010-09-17 17:31:01 +00001779 const int
1780 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001781
cristye7cc7cf2010-09-21 13:26:47 +00001782 assert(image != (const Image *) NULL);
1783 assert(image->signature == MagickSignature);
1784 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001785 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001786 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001787 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001788 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001789}
1790
1791/*
1792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1793% %
1794% %
1795% %
1796% G e t A u t h e n t i c P i x e l Q u e u e %
1797% %
1798% %
1799% %
1800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1801%
1802% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1803% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1804%
1805% The format of the GetAuthenticPixelQueue() method is:
1806%
1807% PixelPacket *GetAuthenticPixelQueue(const Image image)
1808%
1809% A description of each parameter follows:
1810%
1811% o image: the image.
1812%
1813*/
1814MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1815{
1816 CacheInfo
1817 *cache_info;
1818
cristy2036f5c2010-09-19 21:18:17 +00001819 const int
1820 id = GetOpenMPThreadId();
1821
cristy3ed852e2009-09-05 21:47:34 +00001822 assert(image != (const Image *) NULL);
1823 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001824 assert(image->cache != (Cache) NULL);
1825 cache_info=(CacheInfo *) image->cache;
1826 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001827 if (cache_info->methods.get_authentic_pixels_from_handler !=
1828 (GetAuthenticPixelsFromHandler) NULL)
1829 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001830 assert(id < (int) cache_info->number_threads);
1831 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001832}
1833
1834/*
1835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1836% %
1837% %
1838% %
1839% G e t A u t h e n t i c P i x e l s %
1840% %
1841% %
1842% %
1843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1844%
1845% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1846% region is successfully accessed, a pointer to a PixelPacket array
1847% representing the region is returned, otherwise NULL is returned.
1848%
1849% The returned pointer may point to a temporary working copy of the pixels
1850% or it may point to the original pixels in memory. Performance is maximized
1851% if the selected region is part of one row, or one or more full rows, since
1852% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001853% if the image is in memory, or in a memory-mapped file. The returned pointer
1854% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001855%
1856% Pixels accessed via the returned pointer represent a simple array of type
1857% PixelPacket. If the image type is CMYK or if the storage class is
1858% PseduoClass, call GetAuthenticIndexQueue() after invoking
1859% GetAuthenticPixels() to obtain the black color component or colormap indexes
1860% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1861% (and/or IndexPacket) array has been updated, the changes must be saved back
1862% to the underlying image using SyncAuthenticPixels() or they may be lost.
1863%
1864% The format of the GetAuthenticPixels() method is:
1865%
cristy5f959472010-05-27 22:19:46 +00001866% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1867% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001868% ExceptionInfo *exception)
1869%
1870% A description of each parameter follows:
1871%
1872% o image: the image.
1873%
1874% o x,y,columns,rows: These values define the perimeter of a region of
1875% pixels.
1876%
1877% o exception: return any errors or warnings in this structure.
1878%
1879*/
cristybb503372010-05-27 20:51:26 +00001880MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1881 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001882 ExceptionInfo *exception)
1883{
1884 CacheInfo
1885 *cache_info;
1886
cristy2036f5c2010-09-19 21:18:17 +00001887 const int
1888 id = GetOpenMPThreadId();
1889
cristy3ed852e2009-09-05 21:47:34 +00001890 assert(image != (Image *) NULL);
1891 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001892 assert(image->cache != (Cache) NULL);
1893 cache_info=(CacheInfo *) image->cache;
1894 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001895 if (cache_info->methods.get_authentic_pixels_handler !=
1896 (GetAuthenticPixelsHandler) NULL)
1897 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1898 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00001899 assert(id < (int) cache_info->number_threads);
1900 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1901 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001902}
1903
1904/*
1905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1906% %
1907% %
1908% %
1909+ G e t A u t h e n t i c P i x e l s C a c h e %
1910% %
1911% %
1912% %
1913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1914%
1915% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1916% as defined by the geometry parameters. A pointer to the pixels is returned
1917% if the pixels are transferred, otherwise a NULL is returned.
1918%
1919% The format of the GetAuthenticPixelsCache() method is:
1920%
cristybb503372010-05-27 20:51:26 +00001921% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1922% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001923% ExceptionInfo *exception)
1924%
1925% A description of each parameter follows:
1926%
1927% o image: the image.
1928%
1929% o x,y,columns,rows: These values define the perimeter of a region of
1930% pixels.
1931%
1932% o exception: return any errors or warnings in this structure.
1933%
1934*/
cristybb503372010-05-27 20:51:26 +00001935static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1936 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001937 ExceptionInfo *exception)
1938{
1939 CacheInfo
1940 *cache_info;
1941
cristy5c9e6f22010-09-17 17:31:01 +00001942 const int
1943 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001944
cristye7cc7cf2010-09-21 13:26:47 +00001945 assert(image != (const Image *) NULL);
1946 assert(image->signature == MagickSignature);
1947 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001948 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001949 if (cache_info == (Cache) NULL)
1950 return((PixelPacket *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001951 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001952 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001953 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1954 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001955}
1956
1957/*
1958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1959% %
1960% %
1961% %
1962+ G e t I m a g e E x t e n t %
1963% %
1964% %
1965% %
1966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1967%
1968% GetImageExtent() returns the extent of the pixels associated with the
1969% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1970%
1971% The format of the GetImageExtent() method is:
1972%
1973% MagickSizeType GetImageExtent(const Image *image)
1974%
1975% A description of each parameter follows:
1976%
1977% o image: the image.
1978%
1979*/
1980MagickExport MagickSizeType GetImageExtent(const Image *image)
1981{
1982 CacheInfo
1983 *cache_info;
1984
cristy5c9e6f22010-09-17 17:31:01 +00001985 const int
1986 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001987
cristy3ed852e2009-09-05 21:47:34 +00001988 assert(image != (Image *) NULL);
1989 assert(image->signature == MagickSignature);
1990 if (image->debug != MagickFalse)
1991 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1992 assert(image->cache != (Cache) NULL);
1993 cache_info=(CacheInfo *) image->cache;
1994 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001995 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001996 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001997}
1998
1999/*
2000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2001% %
2002% %
2003% %
2004+ G e t I m a g e P i x e l C a c h e %
2005% %
2006% %
2007% %
2008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2009%
2010% GetImagePixelCache() ensures that there is only a single reference to the
2011% pixel cache to be modified, updating the provided cache pointer to point to
2012% a clone of the original pixel cache if necessary.
2013%
2014% The format of the GetImagePixelCache method is:
2015%
2016% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2017% ExceptionInfo *exception)
2018%
2019% A description of each parameter follows:
2020%
2021% o image: the image.
2022%
2023% o clone: any value other than MagickFalse clones the cache pixels.
2024%
2025% o exception: return any errors or warnings in this structure.
2026%
2027*/
cristy3ed852e2009-09-05 21:47:34 +00002028static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2029{
2030 CacheInfo
2031 *cache_info;
2032
2033 /*
2034 Does the image match the pixel cache morphology?
2035 */
2036 cache_info=(CacheInfo *) image->cache;
2037 if ((image->storage_class != cache_info->storage_class) ||
2038 (image->colorspace != cache_info->colorspace) ||
cristy0d267172011-04-25 20:13:48 +00002039 (image->channels != cache_info->channels) ||
cristy3ed852e2009-09-05 21:47:34 +00002040 (image->columns != cache_info->columns) ||
2041 (image->rows != cache_info->rows) ||
2042 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2043 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2044 return(MagickFalse);
2045 return(MagickTrue);
2046}
2047
cristy77ff0282010-09-13 00:51:10 +00002048static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2049 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002050{
2051 CacheInfo
2052 *cache_info;
2053
cristy3ed852e2009-09-05 21:47:34 +00002054 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002055 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002056 status;
2057
cristy50a10922010-02-15 18:35:25 +00002058 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002059 cpu_throttle = 0,
2060 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002061 time_limit = 0;
2062
cristy1ea34962010-07-01 19:49:21 +00002063 static time_t
cristya21afde2010-07-02 00:45:40 +00002064 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002065
cristyc4f9f132010-03-04 18:50:01 +00002066 status=MagickTrue;
2067 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002068 if (cpu_throttle == 0)
2069 {
2070 char
2071 *limit;
2072
2073 /*
2074 Set CPU throttle in milleseconds.
2075 */
2076 cpu_throttle=MagickResourceInfinity;
2077 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2078 if (limit == (char *) NULL)
2079 limit=GetPolicyValue("throttle");
2080 if (limit != (char *) NULL)
2081 {
2082 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2083 limit=DestroyString(limit);
2084 }
2085 }
2086 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2087 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002088 if (time_limit == 0)
2089 {
cristy6ebe97c2010-07-03 01:17:28 +00002090 /*
2091 Set the exire time in seconds.
2092 */
cristy1ea34962010-07-01 19:49:21 +00002093 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002094 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002095 }
2096 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002097 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002098 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002099 assert(image->cache != (Cache) NULL);
2100 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002101 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002102 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002103 {
cristyceb55ee2010-11-06 16:05:49 +00002104 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002105 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002106 {
cristyceb55ee2010-11-06 16:05:49 +00002107 Image
2108 clone_image;
2109
2110 CacheInfo
2111 *clone_info;
2112
2113 /*
2114 Clone pixel cache.
2115 */
2116 clone_image=(*image);
2117 clone_image.semaphore=AllocateSemaphoreInfo();
2118 clone_image.reference_count=1;
2119 clone_image.cache=ClonePixelCache(cache_info);
2120 clone_info=(CacheInfo *) clone_image.cache;
2121 status=OpenPixelCache(&clone_image,IOMode,exception);
2122 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002123 {
cristy5a7fbfb2010-11-06 16:10:59 +00002124 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002125 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002126 if (status != MagickFalse)
2127 {
cristyceb55ee2010-11-06 16:05:49 +00002128 destroy=MagickTrue;
2129 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002130 }
2131 }
cristyceb55ee2010-11-06 16:05:49 +00002132 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002133 }
cristyceb55ee2010-11-06 16:05:49 +00002134 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002135 }
cristy4320e0e2009-09-10 15:00:08 +00002136 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002137 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002138 if (status != MagickFalse)
2139 {
2140 /*
2141 Ensure the image matches the pixel cache morphology.
2142 */
2143 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002144 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002145 if (image->colorspace == GRAYColorspace)
2146 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002147 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2148 status=OpenPixelCache(image,IOMode,exception);
2149 }
cristyf84a1932010-01-03 18:00:18 +00002150 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002151 if (status == MagickFalse)
2152 return((Cache) NULL);
2153 return(image->cache);
2154}
2155
2156/*
2157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158% %
2159% %
2160% %
2161% G e t O n e A u t h e n t i c P i x e l %
2162% %
2163% %
2164% %
2165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166%
2167% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2168% location. The image background color is returned if an error occurs.
2169%
2170% The format of the GetOneAuthenticPixel() method is:
2171%
cristybb503372010-05-27 20:51:26 +00002172% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2173% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002174%
2175% A description of each parameter follows:
2176%
2177% o image: the image.
2178%
2179% o x,y: These values define the location of the pixel to return.
2180%
2181% o pixel: return a pixel at the specified (x,y) location.
2182%
2183% o exception: return any errors or warnings in this structure.
2184%
2185*/
cristyacbbb7c2010-06-30 18:56:48 +00002186MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2187 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002188{
2189 CacheInfo
2190 *cache_info;
2191
cristy2036f5c2010-09-19 21:18:17 +00002192 PixelPacket
2193 *pixels;
2194
cristy3ed852e2009-09-05 21:47:34 +00002195 assert(image != (Image *) NULL);
2196 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002197 assert(image->cache != (Cache) NULL);
2198 cache_info=(CacheInfo *) image->cache;
2199 assert(cache_info->signature == MagickSignature);
2200 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002201 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2202 (GetOneAuthenticPixelFromHandler) NULL)
2203 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2204 pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002205 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2206 if (pixels == (PixelPacket *) NULL)
2207 return(MagickFalse);
2208 *pixel=(*pixels);
2209 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002210}
2211
2212/*
2213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2214% %
2215% %
2216% %
2217+ 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 %
2218% %
2219% %
2220% %
2221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2222%
2223% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2224% location. The image background color is returned if an error occurs.
2225%
2226% The format of the GetOneAuthenticPixelFromCache() method is:
2227%
2228% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002229% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2230% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002231%
2232% A description of each parameter follows:
2233%
2234% o image: the image.
2235%
2236% o x,y: These values define the location of the pixel to return.
2237%
2238% o pixel: return a pixel at the specified (x,y) location.
2239%
2240% o exception: return any errors or warnings in this structure.
2241%
2242*/
2243static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002244 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002245{
cristy098f78c2010-09-23 17:28:44 +00002246 CacheInfo
2247 *cache_info;
2248
2249 const int
2250 id = GetOpenMPThreadId();
2251
cristy3ed852e2009-09-05 21:47:34 +00002252 PixelPacket
2253 *pixels;
2254
cristy0158a4b2010-09-20 13:59:45 +00002255 assert(image != (const Image *) NULL);
2256 assert(image->signature == MagickSignature);
2257 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002258 cache_info=(CacheInfo *) image->cache;
2259 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002260 *pixel=image->background_color;
cristy098f78c2010-09-23 17:28:44 +00002261 assert(id < (int) cache_info->number_threads);
2262 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2263 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002264 if (pixels == (PixelPacket *) NULL)
2265 return(MagickFalse);
2266 *pixel=(*pixels);
2267 return(MagickTrue);
2268}
2269
2270/*
2271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2272% %
2273% %
2274% %
2275% G e t O n e V i r t u a l M a g i c k P i x e l %
2276% %
2277% %
2278% %
2279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2280%
2281% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2282% location. The image background color is returned if an error occurs. If
2283% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2284%
2285% The format of the GetOneVirtualMagickPixel() method is:
2286%
2287% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002288% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002289% ExceptionInfo exception)
2290%
2291% A description of each parameter follows:
2292%
2293% o image: the image.
2294%
2295% o x,y: these values define the location of the pixel to return.
2296%
2297% o pixel: return a pixel at the specified (x,y) location.
2298%
2299% o exception: return any errors or warnings in this structure.
2300%
2301*/
2302MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002303 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2304 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002305{
2306 CacheInfo
2307 *cache_info;
2308
cristy0158a4b2010-09-20 13:59:45 +00002309 const int
2310 id = GetOpenMPThreadId();
2311
cristy3ed852e2009-09-05 21:47:34 +00002312 register const IndexPacket
2313 *indexes;
2314
2315 register const PixelPacket
cristy0158a4b2010-09-20 13:59:45 +00002316 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002317
2318 assert(image != (const Image *) NULL);
2319 assert(image->signature == MagickSignature);
2320 assert(image->cache != (Cache) NULL);
2321 cache_info=(CacheInfo *) image->cache;
2322 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002323 assert(id < (int) cache_info->number_threads);
2324 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2325 1UL,1UL,cache_info->nexus_info[id],exception);
cristye7cc7cf2010-09-21 13:26:47 +00002326 GetMagickPixelPacket(image,pixel);
cristy0158a4b2010-09-20 13:59:45 +00002327 if (pixels == (const PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002328 return(MagickFalse);
cristy098f78c2010-09-23 17:28:44 +00002329 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
cristy0158a4b2010-09-20 13:59:45 +00002330 SetMagickPixelPacket(image,pixels,indexes,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002331 return(MagickTrue);
2332}
2333
2334/*
2335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2336% %
2337% %
2338% %
2339% G e t O n e V i r t u a l M e t h o d P i x e l %
2340% %
2341% %
2342% %
2343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2344%
2345% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2346% location as defined by specified pixel method. The image background color
2347% is returned if an error occurs. If you plan to modify the pixel, use
2348% GetOneAuthenticPixel() instead.
2349%
2350% The format of the GetOneVirtualMethodPixel() method is:
2351%
2352% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002353% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2354% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002355%
2356% A description of each parameter follows:
2357%
2358% o image: the image.
2359%
2360% o virtual_pixel_method: the virtual pixel method.
2361%
2362% o x,y: These values define the location of the pixel to return.
2363%
2364% o pixel: return a pixel at the specified (x,y) location.
2365%
2366% o exception: return any errors or warnings in this structure.
2367%
2368*/
2369MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002370 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002371 PixelPacket *pixel,ExceptionInfo *exception)
2372{
cristy3ed852e2009-09-05 21:47:34 +00002373 CacheInfo
2374 *cache_info;
2375
cristy0158a4b2010-09-20 13:59:45 +00002376 const int
2377 id = GetOpenMPThreadId();
2378
cristy2036f5c2010-09-19 21:18:17 +00002379 const PixelPacket
2380 *pixels;
2381
cristy3ed852e2009-09-05 21:47:34 +00002382 assert(image != (const Image *) NULL);
2383 assert(image->signature == MagickSignature);
2384 assert(image->cache != (Cache) NULL);
2385 cache_info=(CacheInfo *) image->cache;
2386 assert(cache_info->signature == MagickSignature);
2387 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002388 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2389 (GetOneVirtualPixelFromHandler) NULL)
2390 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2391 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002392 assert(id < (int) cache_info->number_threads);
2393 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2394 cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002395 if (pixels == (const PixelPacket *) NULL)
2396 return(MagickFalse);
2397 *pixel=(*pixels);
2398 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002399}
2400
2401/*
2402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403% %
2404% %
2405% %
2406% G e t O n e V i r t u a l P i x e l %
2407% %
2408% %
2409% %
2410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2411%
2412% GetOneVirtualPixel() returns a single virtual pixel at the specified
2413% (x,y) location. The image background color is returned if an error occurs.
2414% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2415%
2416% The format of the GetOneVirtualPixel() method is:
2417%
cristybb503372010-05-27 20:51:26 +00002418% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2419% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002420%
2421% A description of each parameter follows:
2422%
2423% o image: the image.
2424%
2425% o x,y: These values define the location of the pixel to return.
2426%
2427% o pixel: return a pixel at the specified (x,y) location.
2428%
2429% o exception: return any errors or warnings in this structure.
2430%
2431*/
2432MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002433 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002434{
cristy3ed852e2009-09-05 21:47:34 +00002435 CacheInfo
2436 *cache_info;
2437
cristy0158a4b2010-09-20 13:59:45 +00002438 const int
2439 id = GetOpenMPThreadId();
2440
cristy2036f5c2010-09-19 21:18:17 +00002441 const PixelPacket
2442 *pixels;
2443
cristy3ed852e2009-09-05 21:47:34 +00002444 assert(image != (const Image *) NULL);
2445 assert(image->signature == MagickSignature);
2446 assert(image->cache != (Cache) NULL);
2447 cache_info=(CacheInfo *) image->cache;
2448 assert(cache_info->signature == MagickSignature);
2449 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002450 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2451 (GetOneVirtualPixelFromHandler) NULL)
2452 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2453 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002454 assert(id < (int) cache_info->number_threads);
2455 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2456 1UL,1UL,cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002457 if (pixels == (const PixelPacket *) NULL)
2458 return(MagickFalse);
2459 *pixel=(*pixels);
2460 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002461}
2462
2463/*
2464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465% %
2466% %
2467% %
2468+ 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 %
2469% %
2470% %
2471% %
2472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2473%
2474% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2475% specified (x,y) location. The image background color is returned if an
2476% error occurs.
2477%
2478% The format of the GetOneVirtualPixelFromCache() method is:
2479%
2480% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002481% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002482% PixelPacket *pixel,ExceptionInfo *exception)
2483%
2484% A description of each parameter follows:
2485%
2486% o image: the image.
2487%
2488% o virtual_pixel_method: the virtual pixel method.
2489%
2490% o x,y: These values define the location of the pixel to return.
2491%
2492% o pixel: return a pixel at the specified (x,y) location.
2493%
2494% o exception: return any errors or warnings in this structure.
2495%
2496*/
2497static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002498 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002499 PixelPacket *pixel,ExceptionInfo *exception)
2500{
cristy0158a4b2010-09-20 13:59:45 +00002501 CacheInfo
2502 *cache_info;
2503
2504 const int
2505 id = GetOpenMPThreadId();
2506
cristy3ed852e2009-09-05 21:47:34 +00002507 const PixelPacket
2508 *pixels;
2509
cristye7cc7cf2010-09-21 13:26:47 +00002510 assert(image != (const Image *) NULL);
2511 assert(image->signature == MagickSignature);
2512 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002513 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002514 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002515 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002516 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002517 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2518 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002519 if (pixels == (const PixelPacket *) NULL)
2520 return(MagickFalse);
2521 *pixel=(*pixels);
2522 return(MagickTrue);
2523}
2524
2525/*
2526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2527% %
2528% %
2529% %
cristy0d267172011-04-25 20:13:48 +00002530+ G e t P i x e l C a c h e C h a n n e l s %
2531% %
2532% %
2533% %
2534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2535%
2536% GetPixelCacheChannels() returns the number of pixel channels associated
2537% with this instance of the pixel cache.
2538%
2539% The format of the GetPixelCacheChannels() method is:
2540%
2541% size_t GetPixelCacheChannels(Cache cache)
2542%
2543% A description of each parameter follows:
2544%
2545% o type: GetPixelCacheChannels returns DirectClass or PseudoClass.
2546%
2547% o cache: the pixel cache.
2548%
2549*/
2550MagickExport size_t GetPixelCacheChannels(const Cache cache)
2551{
2552 CacheInfo
2553 *cache_info;
2554
2555 assert(cache != (Cache) NULL);
2556 cache_info=(CacheInfo *) cache;
2557 assert(cache_info->signature == MagickSignature);
2558 if (cache_info->debug != MagickFalse)
2559 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2560 cache_info->filename);
2561 return(cache_info->channels);
2562}
2563
2564/*
2565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2566% %
2567% %
2568% %
cristy3ed852e2009-09-05 21:47:34 +00002569+ G e t P i x e l C a c h e C o l o r s p a c e %
2570% %
2571% %
2572% %
2573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2574%
2575% GetPixelCacheColorspace() returns the class type of the pixel cache.
2576%
2577% The format of the GetPixelCacheColorspace() method is:
2578%
2579% Colorspace GetPixelCacheColorspace(Cache cache)
2580%
2581% A description of each parameter follows:
2582%
2583% o cache: the pixel cache.
2584%
2585*/
2586MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2587{
2588 CacheInfo
2589 *cache_info;
2590
2591 assert(cache != (Cache) NULL);
2592 cache_info=(CacheInfo *) cache;
2593 assert(cache_info->signature == MagickSignature);
2594 if (cache_info->debug != MagickFalse)
2595 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2596 cache_info->filename);
2597 return(cache_info->colorspace);
2598}
2599
2600/*
2601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2602% %
2603% %
2604% %
2605+ G e t P i x e l C a c h e M e t h o d s %
2606% %
2607% %
2608% %
2609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2610%
2611% GetPixelCacheMethods() initializes the CacheMethods structure.
2612%
2613% The format of the GetPixelCacheMethods() method is:
2614%
2615% void GetPixelCacheMethods(CacheMethods *cache_methods)
2616%
2617% A description of each parameter follows:
2618%
2619% o cache_methods: Specifies a pointer to a CacheMethods structure.
2620%
2621*/
2622MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2623{
2624 assert(cache_methods != (CacheMethods *) NULL);
2625 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2626 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2627 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2628 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2629 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2630 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2631 cache_methods->get_authentic_indexes_from_handler=
2632 GetAuthenticIndexesFromCache;
2633 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2634 cache_methods->get_one_authentic_pixel_from_handler=
2635 GetOneAuthenticPixelFromCache;
2636 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2637 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2638 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2639}
2640
2641/*
2642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2643% %
2644% %
2645% %
2646+ G e t P i x e l C a c h e N e x u s E x t e n t %
2647% %
2648% %
2649% %
2650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2651%
2652% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2653% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2654%
2655% The format of the GetPixelCacheNexusExtent() method is:
2656%
2657% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2658% NexusInfo *nexus_info)
2659%
2660% A description of each parameter follows:
2661%
2662% o nexus_info: the nexus info.
2663%
2664*/
2665MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2666 NexusInfo *nexus_info)
2667{
2668 CacheInfo
2669 *cache_info;
2670
2671 MagickSizeType
2672 extent;
2673
cristye7cc7cf2010-09-21 13:26:47 +00002674 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002675 cache_info=(CacheInfo *) cache;
2676 assert(cache_info->signature == MagickSignature);
2677 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2678 if (extent == 0)
2679 return((MagickSizeType) cache_info->columns*cache_info->rows);
2680 return(extent);
2681}
2682
2683/*
2684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2685% %
2686% %
2687% %
2688+ 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 %
2689% %
2690% %
2691% %
2692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2693%
2694% GetPixelCacheNexusIndexes() returns the indexes associated with the
2695% specified cache nexus.
2696%
2697% The format of the GetPixelCacheNexusIndexes() method is:
2698%
2699% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2700% NexusInfo *nexus_info)
2701%
2702% A description of each parameter follows:
2703%
2704% o cache: the pixel cache.
2705%
2706% o nexus_info: the cache nexus to return the colormap indexes.
2707%
2708*/
2709MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2710 NexusInfo *nexus_info)
2711{
2712 CacheInfo
2713 *cache_info;
2714
cristye7cc7cf2010-09-21 13:26:47 +00002715 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002716 cache_info=(CacheInfo *) cache;
2717 assert(cache_info->signature == MagickSignature);
2718 if (cache_info->storage_class == UndefinedClass)
2719 return((IndexPacket *) NULL);
2720 return(nexus_info->indexes);
2721}
2722
2723/*
2724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2725% %
2726% %
2727% %
2728+ G e t P i x e l C a c h e N e x u s P i x e l s %
2729% %
2730% %
2731% %
2732%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2733%
2734% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2735% cache nexus.
2736%
2737% The format of the GetPixelCacheNexusPixels() method is:
2738%
2739% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2740% NexusInfo *nexus_info)
2741%
2742% A description of each parameter follows:
2743%
2744% o cache: the pixel cache.
2745%
2746% o nexus_info: the cache nexus to return the pixels.
2747%
2748*/
2749MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2750 NexusInfo *nexus_info)
2751{
2752 CacheInfo
2753 *cache_info;
2754
cristye7cc7cf2010-09-21 13:26:47 +00002755 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002756 cache_info=(CacheInfo *) cache;
2757 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002758 if (cache_info->storage_class == UndefinedClass)
2759 return((PixelPacket *) NULL);
2760 return(nexus_info->pixels);
2761}
2762
2763/*
2764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2765% %
2766% %
2767% %
cristy056ba772010-01-02 23:33:54 +00002768+ G e t P i x e l C a c h e P i x e l s %
2769% %
2770% %
2771% %
2772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2773%
2774% GetPixelCachePixels() returns the pixels associated with the specified image.
2775%
2776% The format of the GetPixelCachePixels() method is:
2777%
cristyf84a1932010-01-03 18:00:18 +00002778% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2779% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002780%
2781% A description of each parameter follows:
2782%
2783% o image: the image.
2784%
2785% o length: the pixel cache length.
2786%
cristyf84a1932010-01-03 18:00:18 +00002787% o exception: return any errors or warnings in this structure.
2788%
cristy056ba772010-01-02 23:33:54 +00002789*/
cristyf84a1932010-01-03 18:00:18 +00002790MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2791 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002792{
2793 CacheInfo
2794 *cache_info;
2795
2796 assert(image != (const Image *) NULL);
2797 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002798 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002799 assert(length != (MagickSizeType *) NULL);
2800 assert(exception != (ExceptionInfo *) NULL);
2801 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002802 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002803 assert(cache_info->signature == MagickSignature);
2804 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002805 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002806 return((void *) NULL);
2807 *length=cache_info->length;
2808 return((void *) cache_info->pixels);
2809}
2810
2811/*
2812%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2813% %
2814% %
2815% %
cristyb32b90a2009-09-07 21:45:48 +00002816+ 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 +00002817% %
2818% %
2819% %
2820%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2821%
2822% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2823%
2824% The format of the GetPixelCacheStorageClass() method is:
2825%
2826% ClassType GetPixelCacheStorageClass(Cache cache)
2827%
2828% A description of each parameter follows:
2829%
2830% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2831%
2832% o cache: the pixel cache.
2833%
2834*/
2835MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2836{
2837 CacheInfo
2838 *cache_info;
2839
2840 assert(cache != (Cache) NULL);
2841 cache_info=(CacheInfo *) cache;
2842 assert(cache_info->signature == MagickSignature);
2843 if (cache_info->debug != MagickFalse)
2844 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2845 cache_info->filename);
2846 return(cache_info->storage_class);
2847}
2848
2849/*
2850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2851% %
2852% %
2853% %
cristyb32b90a2009-09-07 21:45:48 +00002854+ G e t P i x e l C a c h e T i l e S i z e %
2855% %
2856% %
2857% %
2858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2859%
2860% GetPixelCacheTileSize() returns the pixel cache tile size.
2861%
2862% The format of the GetPixelCacheTileSize() method is:
2863%
cristybb503372010-05-27 20:51:26 +00002864% void GetPixelCacheTileSize(const Image *image,size_t *width,
2865% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002866%
2867% A description of each parameter follows:
2868%
2869% o image: the image.
2870%
2871% o width: the optimize cache tile width in pixels.
2872%
2873% o height: the optimize cache tile height in pixels.
2874%
2875*/
cristybb503372010-05-27 20:51:26 +00002876MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2877 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002878{
cristyb32b90a2009-09-07 21:45:48 +00002879 assert(image != (Image *) NULL);
2880 assert(image->signature == MagickSignature);
2881 if (image->debug != MagickFalse)
2882 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyb32b90a2009-09-07 21:45:48 +00002883 *width=2048UL/sizeof(PixelPacket);
2884 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002885 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002886 *height=(*width);
2887}
2888
2889/*
2890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891% %
2892% %
2893% %
2894+ G e t P i x e l C a c h e T y p e %
2895% %
2896% %
2897% %
2898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2899%
2900% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2901%
2902% The format of the GetPixelCacheType() method is:
2903%
2904% CacheType GetPixelCacheType(const Image *image)
2905%
2906% A description of each parameter follows:
2907%
2908% o image: the image.
2909%
2910*/
2911MagickExport CacheType GetPixelCacheType(const Image *image)
2912{
2913 CacheInfo
2914 *cache_info;
2915
2916 assert(image != (Image *) NULL);
2917 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002918 assert(image->cache != (Cache) NULL);
2919 cache_info=(CacheInfo *) image->cache;
2920 assert(cache_info->signature == MagickSignature);
2921 return(cache_info->type);
2922}
2923
2924/*
2925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2926% %
2927% %
2928% %
cristy3ed852e2009-09-05 21:47:34 +00002929+ 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 %
2930% %
2931% %
2932% %
2933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2934%
2935% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2936% pixel cache. A virtual pixel is any pixel access that is outside the
2937% boundaries of the image cache.
2938%
2939% The format of the GetPixelCacheVirtualMethod() method is:
2940%
2941% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2942%
2943% A description of each parameter follows:
2944%
2945% o image: the image.
2946%
2947*/
2948MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2949{
2950 CacheInfo
2951 *cache_info;
2952
2953 assert(image != (Image *) NULL);
2954 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002955 assert(image->cache != (Cache) NULL);
2956 cache_info=(CacheInfo *) image->cache;
2957 assert(cache_info->signature == MagickSignature);
2958 return(cache_info->virtual_pixel_method);
2959}
2960
2961/*
2962%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2963% %
2964% %
2965% %
2966+ 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 %
2967% %
2968% %
2969% %
2970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2971%
2972% GetVirtualIndexesFromCache() returns the indexes associated with the last
2973% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2974%
2975% The format of the GetVirtualIndexesFromCache() method is:
2976%
2977% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2978%
2979% A description of each parameter follows:
2980%
2981% o image: the image.
2982%
2983*/
2984static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2985{
2986 CacheInfo
2987 *cache_info;
2988
cristy5c9e6f22010-09-17 17:31:01 +00002989 const int
2990 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002991
cristye7cc7cf2010-09-21 13:26:47 +00002992 assert(image != (const Image *) NULL);
2993 assert(image->signature == MagickSignature);
2994 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002995 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002996 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002997 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002998 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002999}
3000
3001/*
3002%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3003% %
3004% %
3005% %
3006+ 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 %
3007% %
3008% %
3009% %
3010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3011%
3012% GetVirtualIndexesFromNexus() returns the indexes associated with the
3013% specified cache nexus.
3014%
3015% The format of the GetVirtualIndexesFromNexus() method is:
3016%
3017% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3018% NexusInfo *nexus_info)
3019%
3020% A description of each parameter follows:
3021%
3022% o cache: the pixel cache.
3023%
3024% o nexus_info: the cache nexus to return the colormap indexes.
3025%
3026*/
3027MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3028 NexusInfo *nexus_info)
3029{
3030 CacheInfo
3031 *cache_info;
3032
cristye7cc7cf2010-09-21 13:26:47 +00003033 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003034 cache_info=(CacheInfo *) cache;
3035 assert(cache_info->signature == MagickSignature);
3036 if (cache_info->storage_class == UndefinedClass)
3037 return((IndexPacket *) NULL);
3038 return(nexus_info->indexes);
3039}
3040
3041/*
3042%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3043% %
3044% %
3045% %
3046% G e t V i r t u a l I n d e x Q u e u e %
3047% %
3048% %
3049% %
3050%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3051%
3052% GetVirtualIndexQueue() returns the virtual black channel or the
3053% colormap indexes associated with the last call to QueueAuthenticPixels() or
3054% GetVirtualPixels(). NULL is returned if the black channel or colormap
3055% indexes are not available.
3056%
3057% The format of the GetVirtualIndexQueue() method is:
3058%
3059% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3060%
3061% A description of each parameter follows:
3062%
3063% o image: the image.
3064%
3065*/
3066MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3067{
3068 CacheInfo
3069 *cache_info;
3070
cristy2036f5c2010-09-19 21:18:17 +00003071 const int
3072 id = GetOpenMPThreadId();
3073
cristy3ed852e2009-09-05 21:47:34 +00003074 assert(image != (const Image *) NULL);
3075 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003076 assert(image->cache != (Cache) NULL);
3077 cache_info=(CacheInfo *) image->cache;
3078 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003079 if (cache_info->methods.get_virtual_indexes_from_handler !=
3080 (GetVirtualIndexesFromHandler) NULL)
3081 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003082 assert(id < (int) cache_info->number_threads);
3083 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003084}
3085
3086/*
3087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3088% %
3089% %
3090% %
3091+ 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 %
3092% %
3093% %
3094% %
3095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3096%
3097% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3098% pixel cache as defined by the geometry parameters. A pointer to the pixels
3099% is returned if the pixels are transferred, otherwise a NULL is returned.
3100%
3101% The format of the GetVirtualPixelsFromNexus() method is:
3102%
3103% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003104% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003105% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3106% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003107%
3108% A description of each parameter follows:
3109%
3110% o image: the image.
3111%
3112% o virtual_pixel_method: the virtual pixel method.
3113%
3114% o x,y,columns,rows: These values define the perimeter of a region of
3115% pixels.
3116%
3117% o nexus_info: the cache nexus to acquire.
3118%
3119% o exception: return any errors or warnings in this structure.
3120%
3121*/
3122
cristybb503372010-05-27 20:51:26 +00003123static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003124 DitherMatrix[64] =
3125 {
3126 0, 48, 12, 60, 3, 51, 15, 63,
3127 32, 16, 44, 28, 35, 19, 47, 31,
3128 8, 56, 4, 52, 11, 59, 7, 55,
3129 40, 24, 36, 20, 43, 27, 39, 23,
3130 2, 50, 14, 62, 1, 49, 13, 61,
3131 34, 18, 46, 30, 33, 17, 45, 29,
3132 10, 58, 6, 54, 9, 57, 5, 53,
3133 42, 26, 38, 22, 41, 25, 37, 21
3134 };
3135
cristybb503372010-05-27 20:51:26 +00003136static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003137{
cristybb503372010-05-27 20:51:26 +00003138 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003139 index;
3140
3141 index=x+DitherMatrix[x & 0x07]-32L;
3142 if (index < 0L)
3143 return(0L);
cristybb503372010-05-27 20:51:26 +00003144 if (index >= (ssize_t) columns)
3145 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003146 return(index);
3147}
3148
cristybb503372010-05-27 20:51:26 +00003149static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003150{
cristybb503372010-05-27 20:51:26 +00003151 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003152 index;
3153
3154 index=y+DitherMatrix[y & 0x07]-32L;
3155 if (index < 0L)
3156 return(0L);
cristybb503372010-05-27 20:51:26 +00003157 if (index >= (ssize_t) rows)
3158 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003159 return(index);
3160}
3161
cristybb503372010-05-27 20:51:26 +00003162static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003163{
3164 if (x < 0L)
3165 return(0L);
cristybb503372010-05-27 20:51:26 +00003166 if (x >= (ssize_t) columns)
3167 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003168 return(x);
3169}
3170
cristybb503372010-05-27 20:51:26 +00003171static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003172{
3173 if (y < 0L)
3174 return(0L);
cristybb503372010-05-27 20:51:26 +00003175 if (y >= (ssize_t) rows)
3176 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003177 return(y);
3178}
3179
cristybb503372010-05-27 20:51:26 +00003180static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003181{
cristybb503372010-05-27 20:51:26 +00003182 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003183}
3184
cristybb503372010-05-27 20:51:26 +00003185static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003186{
cristybb503372010-05-27 20:51:26 +00003187 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003188}
3189
3190/*
3191 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3192 returns not only the quotient (tile the offset falls in) but also the positive
3193 remainer within that tile such that 0 <= remainder < extent. This method is
3194 essentially a ldiv() using a floored modulo division rather than the normal
3195 default truncated modulo division.
3196*/
cristybb503372010-05-27 20:51:26 +00003197static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3198 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003199{
3200 MagickModulo
3201 modulo;
3202
cristybb503372010-05-27 20:51:26 +00003203 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003204 if (offset < 0L)
3205 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003206 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003207 return(modulo);
3208}
3209
3210MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003211 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3212 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003213 ExceptionInfo *exception)
3214{
3215 CacheInfo
3216 *cache_info;
3217
cristyc3ec0d42010-04-07 01:18:08 +00003218 IndexPacket
3219 virtual_index;
3220
cristy3ed852e2009-09-05 21:47:34 +00003221 MagickOffsetType
3222 offset;
3223
3224 MagickSizeType
3225 length,
3226 number_pixels;
3227
3228 NexusInfo
3229 **virtual_nexus;
3230
3231 PixelPacket
3232 *pixels,
3233 virtual_pixel;
3234
3235 RectangleInfo
3236 region;
3237
3238 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003239 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003240
3241 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003242 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003243
3244 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003245 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003246
cristye076a6e2010-08-15 19:59:43 +00003247 register PixelPacket
3248 *restrict q;
3249
cristybb503372010-05-27 20:51:26 +00003250 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003251 u,
3252 v;
3253
cristy3ed852e2009-09-05 21:47:34 +00003254 /*
3255 Acquire pixels.
3256 */
cristye7cc7cf2010-09-21 13:26:47 +00003257 assert(image != (const Image *) NULL);
3258 assert(image->signature == MagickSignature);
3259 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003260 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003261 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003262 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003263 return((const PixelPacket *) NULL);
3264 region.x=x;
3265 region.y=y;
3266 region.width=columns;
3267 region.height=rows;
3268 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3269 if (pixels == (PixelPacket *) NULL)
3270 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003271 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3272 nexus_info->region.x;
3273 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3274 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003275 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3276 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003277 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3278 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003279 {
3280 MagickBooleanType
3281 status;
3282
3283 /*
3284 Pixel request is inside cache extents.
3285 */
3286 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3287 return(pixels);
3288 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3289 if (status == MagickFalse)
3290 return((const PixelPacket *) NULL);
3291 if ((cache_info->storage_class == PseudoClass) ||
3292 (cache_info->colorspace == CMYKColorspace))
3293 {
3294 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3295 if (status == MagickFalse)
3296 return((const PixelPacket *) NULL);
3297 }
3298 return(pixels);
3299 }
3300 /*
3301 Pixel request is outside cache extents.
3302 */
3303 q=pixels;
3304 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3305 virtual_nexus=AcquirePixelCacheNexus(1);
3306 if (virtual_nexus == (NexusInfo **) NULL)
3307 {
3308 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3309 "UnableToGetCacheNexus","`%s'",image->filename);
3310 return((const PixelPacket *) NULL);
3311 }
3312 switch (virtual_pixel_method)
3313 {
3314 case BlackVirtualPixelMethod:
3315 {
cristyef618312011-06-25 12:26:44 +00003316 SetPixelRed(&virtual_pixel,0);
3317 SetPixelGreen(&virtual_pixel,0);
3318 SetPixelBlue(&virtual_pixel,0);
3319 SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003320 break;
3321 }
3322 case GrayVirtualPixelMethod:
3323 {
cristyef618312011-06-25 12:26:44 +00003324 SetPixelRed(&virtual_pixel,QuantumRange/2);
3325 SetPixelGreen(&virtual_pixel,QuantumRange/2);
3326 SetPixelBlue(&virtual_pixel,QuantumRange/2);
3327 SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003328 break;
3329 }
3330 case TransparentVirtualPixelMethod:
3331 {
cristyef618312011-06-25 12:26:44 +00003332 SetPixelRed(&virtual_pixel,0);
3333 SetPixelGreen(&virtual_pixel,0);
3334 SetPixelBlue(&virtual_pixel,0);
3335 SetPixelOpacity(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003336 break;
3337 }
3338 case MaskVirtualPixelMethod:
3339 case WhiteVirtualPixelMethod:
3340 {
cristyef618312011-06-25 12:26:44 +00003341 SetPixelRed(&virtual_pixel,QuantumRange);
3342 SetPixelGreen(&virtual_pixel,QuantumRange);
3343 SetPixelBlue(&virtual_pixel,QuantumRange);
3344 SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003345 break;
3346 }
3347 default:
3348 {
3349 virtual_pixel=image->background_color;
3350 break;
3351 }
3352 }
cristyc3ec0d42010-04-07 01:18:08 +00003353 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003354 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003355 {
cristybb503372010-05-27 20:51:26 +00003356 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003357 {
3358 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003359 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003360 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3361 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003362 {
3363 MagickModulo
3364 x_modulo,
3365 y_modulo;
3366
3367 /*
3368 Transfer a single pixel.
3369 */
3370 length=(MagickSizeType) 1;
3371 switch (virtual_pixel_method)
3372 {
3373 case BackgroundVirtualPixelMethod:
3374 case ConstantVirtualPixelMethod:
3375 case BlackVirtualPixelMethod:
3376 case GrayVirtualPixelMethod:
3377 case TransparentVirtualPixelMethod:
3378 case MaskVirtualPixelMethod:
3379 case WhiteVirtualPixelMethod:
3380 {
3381 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003382 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003383 break;
3384 }
3385 case EdgeVirtualPixelMethod:
3386 default:
3387 {
3388 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003389 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003390 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003391 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003392 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003393 break;
3394 }
3395 case RandomVirtualPixelMethod:
3396 {
3397 if (cache_info->random_info == (RandomInfo *) NULL)
3398 cache_info->random_info=AcquireRandomInfo();
3399 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003400 RandomX(cache_info->random_info,cache_info->columns),
3401 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003402 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003403 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003404 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003405 break;
3406 }
3407 case DitherVirtualPixelMethod:
3408 {
3409 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003410 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003411 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003412 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003413 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003414 break;
3415 }
3416 case TileVirtualPixelMethod:
3417 {
3418 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3419 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3420 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003421 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003422 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003423 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003424 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003425 break;
3426 }
3427 case MirrorVirtualPixelMethod:
3428 {
3429 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3430 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003431 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003432 x_modulo.remainder-1L;
3433 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3434 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003435 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003436 y_modulo.remainder-1L;
3437 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003438 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003439 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003440 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003441 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003442 break;
3443 }
3444 case CheckerTileVirtualPixelMethod:
3445 {
3446 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3447 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3448 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3449 {
3450 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003451 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003452 break;
3453 }
3454 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003455 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003456 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003457 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003458 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003459 break;
3460 }
3461 case HorizontalTileVirtualPixelMethod:
3462 {
cristybb503372010-05-27 20:51:26 +00003463 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003464 {
3465 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003466 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003467 break;
3468 }
3469 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3470 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3471 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003472 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003473 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003474 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003475 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003476 break;
3477 }
3478 case VerticalTileVirtualPixelMethod:
3479 {
cristybb503372010-05-27 20:51:26 +00003480 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003481 {
3482 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003483 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003484 break;
3485 }
3486 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3487 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3488 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003489 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003490 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003491 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003492 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003493 break;
3494 }
3495 case HorizontalTileEdgeVirtualPixelMethod:
3496 {
3497 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3498 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003499 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003500 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003501 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003502 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003503 break;
3504 }
3505 case VerticalTileEdgeVirtualPixelMethod:
3506 {
3507 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3508 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003509 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003510 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003511 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003512 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003513 break;
3514 }
3515 }
3516 if (p == (const PixelPacket *) NULL)
3517 break;
3518 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003519 if ((indexes != (IndexPacket *) NULL) &&
3520 (virtual_indexes != (const IndexPacket *) NULL))
3521 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003522 continue;
3523 }
3524 /*
3525 Transfer a run of pixels.
3526 */
3527 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristy0a36c742010-10-03 02:10:53 +00003528 (size_t) length,1UL,*virtual_nexus,exception);
cristy3ed852e2009-09-05 21:47:34 +00003529 if (p == (const PixelPacket *) NULL)
3530 break;
cristy0a36c742010-10-03 02:10:53 +00003531 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
cristy8f036fe2010-09-18 02:02:00 +00003532 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003533 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003534 if ((indexes != (IndexPacket *) NULL) &&
3535 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003536 {
cristy8f036fe2010-09-18 02:02:00 +00003537 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003538 sizeof(*virtual_indexes));
3539 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003540 }
3541 }
3542 }
3543 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3544 return(pixels);
3545}
3546
3547/*
3548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3549% %
3550% %
3551% %
3552+ G e t V i r t u a l P i x e l C a c h e %
3553% %
3554% %
3555% %
3556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3557%
3558% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3559% cache as defined by the geometry parameters. A pointer to the pixels
3560% is returned if the pixels are transferred, otherwise a NULL is returned.
3561%
3562% The format of the GetVirtualPixelCache() method is:
3563%
3564% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003565% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3566% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003567% ExceptionInfo *exception)
3568%
3569% A description of each parameter follows:
3570%
3571% o image: the image.
3572%
3573% o virtual_pixel_method: the virtual pixel method.
3574%
3575% o x,y,columns,rows: These values define the perimeter of a region of
3576% pixels.
3577%
3578% o exception: return any errors or warnings in this structure.
3579%
3580*/
3581static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003582 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3583 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003584{
3585 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003586 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003587
cristy5c9e6f22010-09-17 17:31:01 +00003588 const int
3589 id = GetOpenMPThreadId();
3590
cristye7cc7cf2010-09-21 13:26:47 +00003591 assert(image != (const Image *) NULL);
3592 assert(image->signature == MagickSignature);
3593 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003594 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003595 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003596 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003597 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3598 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003599}
3600
3601/*
3602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3603% %
3604% %
3605% %
3606% G e t V i r t u a l P i x e l Q u e u e %
3607% %
3608% %
3609% %
3610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3611%
3612% GetVirtualPixelQueue() returns the virtual pixels associated with the
3613% last call to QueueAuthenticPixels() or GetVirtualPixels().
3614%
3615% The format of the GetVirtualPixelQueue() method is:
3616%
3617% const PixelPacket *GetVirtualPixelQueue(const Image image)
3618%
3619% A description of each parameter follows:
3620%
3621% o image: the image.
3622%
3623*/
3624MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3625{
3626 CacheInfo
3627 *cache_info;
3628
cristy2036f5c2010-09-19 21:18:17 +00003629 const int
3630 id = GetOpenMPThreadId();
3631
cristy3ed852e2009-09-05 21:47:34 +00003632 assert(image != (const Image *) NULL);
3633 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003634 assert(image->cache != (Cache) NULL);
3635 cache_info=(CacheInfo *) image->cache;
3636 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003637 if (cache_info->methods.get_virtual_pixels_handler !=
3638 (GetVirtualPixelsHandler) NULL)
3639 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003640 assert(id < (int) cache_info->number_threads);
3641 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003642}
3643
3644/*
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646% %
3647% %
3648% %
3649% G e t V i r t u a l P i x e l s %
3650% %
3651% %
3652% %
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654%
3655% GetVirtualPixels() returns an immutable pixel region. If the
3656% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003657% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003658% copy of the pixels or it may point to the original pixels in memory.
3659% Performance is maximized if the selected region is part of one row, or one
3660% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003661% (without a copy) if the image is in memory, or in a memory-mapped file. The
3662% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003663%
3664% Pixels accessed via the returned pointer represent a simple array of type
3665% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3666% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3667% the black color component or to obtain the colormap indexes (of type
3668% IndexPacket) corresponding to the region.
3669%
3670% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3671%
3672% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3673% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3674% GetCacheViewAuthenticPixels() instead.
3675%
3676% The format of the GetVirtualPixels() method is:
3677%
cristybb503372010-05-27 20:51:26 +00003678% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3679% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003680% ExceptionInfo *exception)
3681%
3682% A description of each parameter follows:
3683%
3684% o image: the image.
3685%
3686% o x,y,columns,rows: These values define the perimeter of a region of
3687% pixels.
3688%
3689% o exception: return any errors or warnings in this structure.
3690%
3691*/
3692MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003693 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3694 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003695{
3696 CacheInfo
3697 *cache_info;
3698
cristy2036f5c2010-09-19 21:18:17 +00003699 const int
3700 id = GetOpenMPThreadId();
3701
cristy3ed852e2009-09-05 21:47:34 +00003702 assert(image != (const Image *) NULL);
3703 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003704 assert(image->cache != (Cache) NULL);
3705 cache_info=(CacheInfo *) image->cache;
3706 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003707 if (cache_info->methods.get_virtual_pixel_handler !=
3708 (GetVirtualPixelHandler) NULL)
3709 return(cache_info->methods.get_virtual_pixel_handler(image,
3710 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003711 assert(id < (int) cache_info->number_threads);
3712 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3713 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003714}
3715
3716/*
3717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3718% %
3719% %
3720% %
3721+ 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 %
3722% %
3723% %
3724% %
3725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3726%
3727% GetVirtualPixelsCache() returns the pixels associated with the last call
3728% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3729%
3730% The format of the GetVirtualPixelsCache() method is:
3731%
3732% PixelPacket *GetVirtualPixelsCache(const Image *image)
3733%
3734% A description of each parameter follows:
3735%
3736% o image: the image.
3737%
3738*/
3739static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3740{
3741 CacheInfo
3742 *cache_info;
3743
cristy5c9e6f22010-09-17 17:31:01 +00003744 const int
3745 id = GetOpenMPThreadId();
3746
cristye7cc7cf2010-09-21 13:26:47 +00003747 assert(image != (const Image *) NULL);
3748 assert(image->signature == MagickSignature);
3749 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003750 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003751 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003752 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003753 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003754}
3755
3756/*
3757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3758% %
3759% %
3760% %
3761+ G e t V i r t u a l P i x e l s N e x u s %
3762% %
3763% %
3764% %
3765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3766%
3767% GetVirtualPixelsNexus() returns the pixels associated with the specified
3768% cache nexus.
3769%
3770% The format of the GetVirtualPixelsNexus() method is:
3771%
3772% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3773% NexusInfo *nexus_info)
3774%
3775% A description of each parameter follows:
3776%
3777% o cache: the pixel cache.
3778%
3779% o nexus_info: the cache nexus to return the colormap pixels.
3780%
3781*/
3782MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3783 NexusInfo *nexus_info)
3784{
3785 CacheInfo
3786 *cache_info;
3787
cristye7cc7cf2010-09-21 13:26:47 +00003788 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003789 cache_info=(CacheInfo *) cache;
3790 assert(cache_info->signature == MagickSignature);
3791 if (cache_info->storage_class == UndefinedClass)
3792 return((PixelPacket *) NULL);
3793 return((const PixelPacket *) nexus_info->pixels);
3794}
3795
3796/*
3797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3798% %
3799% %
3800% %
3801+ M a s k P i x e l C a c h e N e x u s %
3802% %
3803% %
3804% %
3805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3806%
3807% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3808% The method returns MagickTrue if the pixel region is masked, otherwise
3809% MagickFalse.
3810%
3811% The format of the MaskPixelCacheNexus() method is:
3812%
3813% MagickBooleanType MaskPixelCacheNexus(Image *image,
3814% NexusInfo *nexus_info,ExceptionInfo *exception)
3815%
3816% A description of each parameter follows:
3817%
3818% o image: the image.
3819%
3820% o nexus_info: the cache nexus to clip.
3821%
3822% o exception: return any errors or warnings in this structure.
3823%
3824*/
3825
3826static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3827 const MagickRealType alpha,const MagickPixelPacket *q,
3828 const MagickRealType beta,MagickPixelPacket *composite)
3829{
3830 MagickRealType
3831 gamma;
3832
3833 if (alpha == TransparentOpacity)
3834 {
3835 *composite=(*q);
3836 return;
3837 }
3838 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3839 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003840 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3841 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3842 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003843 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3844 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3845}
3846
3847static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3848 ExceptionInfo *exception)
3849{
3850 CacheInfo
3851 *cache_info;
3852
3853 MagickPixelPacket
3854 alpha,
3855 beta;
3856
3857 MagickSizeType
3858 number_pixels;
3859
3860 NexusInfo
3861 **clip_nexus,
3862 **image_nexus;
3863
3864 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003865 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003866
3867 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003868 *restrict nexus_indexes,
3869 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003870
cristy3ed852e2009-09-05 21:47:34 +00003871 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003872 *restrict p,
3873 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003874
cristye076a6e2010-08-15 19:59:43 +00003875 register ssize_t
3876 i;
3877
cristy3ed852e2009-09-05 21:47:34 +00003878 /*
3879 Apply clip mask.
3880 */
3881 if (image->debug != MagickFalse)
3882 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3883 if (image->mask == (Image *) NULL)
3884 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003885 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003886 if (cache_info == (Cache) NULL)
3887 return(MagickFalse);
3888 image_nexus=AcquirePixelCacheNexus(1);
3889 clip_nexus=AcquirePixelCacheNexus(1);
3890 if ((image_nexus == (NexusInfo **) NULL) ||
3891 (clip_nexus == (NexusInfo **) NULL))
3892 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003893 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3894 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3895 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003896 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3897 q=nexus_info->pixels;
3898 nexus_indexes=nexus_info->indexes;
3899 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3900 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3901 nexus_info->region.height,clip_nexus[0],&image->exception);
3902 GetMagickPixelPacket(image,&alpha);
3903 GetMagickPixelPacket(image,&beta);
3904 number_pixels=(MagickSizeType) nexus_info->region.width*
3905 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003906 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003907 {
3908 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3909 break;
3910 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3911 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3912 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3913 &alpha,alpha.opacity,&beta);
cristyef618312011-06-25 12:26:44 +00003914 SetPixelRed(q,ClampToQuantum(beta.red));
3915 SetPixelGreen(q,ClampToQuantum(beta.green));
3916 SetPixelBlue(q,ClampToQuantum(beta.blue));
3917 SetPixelOpacity(q,ClampToQuantum(beta.opacity));
cristy3ed852e2009-09-05 21:47:34 +00003918 if (cache_info->active_index_channel != MagickFalse)
cristyef618312011-06-25 12:26:44 +00003919 SetPixelIndex(nexus_indexes+i,GetPixelIndex(indexes+i));
cristy3ed852e2009-09-05 21:47:34 +00003920 p++;
3921 q++;
3922 r++;
3923 }
3924 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3925 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003926 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003927 return(MagickFalse);
3928 return(MagickTrue);
3929}
3930
3931/*
3932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3933% %
3934% %
3935% %
3936+ O p e n P i x e l C a c h e %
3937% %
3938% %
3939% %
3940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3941%
3942% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3943% dimensions, allocating space for the image pixels and optionally the
3944% colormap indexes, and memory mapping the cache if it is disk based. The
3945% cache nexus array is initialized as well.
3946%
3947% The format of the OpenPixelCache() method is:
3948%
3949% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3950% ExceptionInfo *exception)
3951%
3952% A description of each parameter follows:
3953%
3954% o image: the image.
3955%
3956% o mode: ReadMode, WriteMode, or IOMode.
3957%
3958% o exception: return any errors or warnings in this structure.
3959%
3960*/
3961
cristyd43a46b2010-01-21 02:13:41 +00003962static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003963{
3964 cache_info->mapped=MagickFalse;
3965 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3966 cache_info->length);
3967 if (cache_info->pixels == (PixelPacket *) NULL)
3968 {
3969 cache_info->mapped=MagickTrue;
3970 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3971 cache_info->length);
3972 }
3973}
3974
3975static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3976{
3977 CacheInfo
3978 *cache_info;
3979
3980 MagickOffsetType
3981 count,
3982 extent,
3983 offset;
3984
3985 cache_info=(CacheInfo *) image->cache;
3986 if (image->debug != MagickFalse)
3987 {
3988 char
3989 format[MaxTextExtent],
3990 message[MaxTextExtent];
3991
cristyb9080c92009-12-01 20:13:26 +00003992 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003993 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003994 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003995 cache_info->cache_filename,cache_info->file,format);
3996 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3997 }
3998 if (length != (MagickSizeType) ((MagickOffsetType) length))
3999 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00004000 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00004001 if (extent < 0)
4002 return(MagickFalse);
4003 if ((MagickSizeType) extent >= length)
4004 return(MagickTrue);
4005 offset=(MagickOffsetType) length-1;
4006 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4007 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4008}
4009
4010static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4011 ExceptionInfo *exception)
4012{
cristy3ed852e2009-09-05 21:47:34 +00004013 CacheInfo
4014 *cache_info,
4015 source_info;
4016
cristyf3a6a9d2010-11-07 21:02:56 +00004017 char
4018 format[MaxTextExtent],
4019 message[MaxTextExtent];
4020
cristy3ed852e2009-09-05 21:47:34 +00004021 MagickSizeType
4022 length,
4023 number_pixels;
4024
4025 MagickStatusType
4026 status;
4027
4028 size_t
cristye076a6e2010-08-15 19:59:43 +00004029 columns,
cristy3ed852e2009-09-05 21:47:34 +00004030 packet_size;
4031
cristye7cc7cf2010-09-21 13:26:47 +00004032 assert(image != (const Image *) NULL);
4033 assert(image->signature == MagickSignature);
4034 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004035 if (image->debug != MagickFalse)
4036 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4037 if ((image->columns == 0) || (image->rows == 0))
4038 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4039 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004040 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004041 source_info=(*cache_info);
4042 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004043 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004044 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004045 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004046 cache_info->rows=image->rows;
4047 cache_info->columns=image->columns;
cristyac319d22011-04-25 20:43:45 +00004048 cache_info->channels=image->channels;
cristy3ed852e2009-09-05 21:47:34 +00004049 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4050 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004051 if (image->ping != MagickFalse)
4052 {
4053 cache_info->storage_class=image->storage_class;
4054 cache_info->colorspace=image->colorspace;
4055 cache_info->type=PingCache;
4056 cache_info->pixels=(PixelPacket *) NULL;
4057 cache_info->indexes=(IndexPacket *) NULL;
4058 cache_info->length=0;
4059 return(MagickTrue);
4060 }
cristy3ed852e2009-09-05 21:47:34 +00004061 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4062 packet_size=sizeof(PixelPacket);
4063 if (cache_info->active_index_channel != MagickFalse)
4064 packet_size+=sizeof(IndexPacket);
4065 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004066 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004067 if (cache_info->columns != columns)
4068 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4069 image->filename);
4070 cache_info->length=length;
4071 status=AcquireMagickResource(AreaResource,cache_info->length);
4072 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4073 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4074 {
4075 status=AcquireMagickResource(MemoryResource,cache_info->length);
4076 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4077 (cache_info->type == MemoryCache))
4078 {
cristyd43a46b2010-01-21 02:13:41 +00004079 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004080 if (cache_info->pixels == (PixelPacket *) NULL)
4081 cache_info->pixels=source_info.pixels;
4082 else
4083 {
4084 /*
4085 Create memory pixel cache.
4086 */
4087 if (image->debug != MagickFalse)
4088 {
cristy97e7a572009-12-05 15:07:53 +00004089 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004090 format);
cristyb51dff52011-05-19 16:55:47 +00004091 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004092 "open %s (%s memory, %.20gx%.20g %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004093 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004094 (double) cache_info->columns,(double) cache_info->rows,
4095 format);
cristy3ed852e2009-09-05 21:47:34 +00004096 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4097 message);
4098 }
4099 cache_info->storage_class=image->storage_class;
4100 cache_info->colorspace=image->colorspace;
4101 cache_info->type=MemoryCache;
4102 cache_info->indexes=(IndexPacket *) NULL;
4103 if (cache_info->active_index_channel != MagickFalse)
4104 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4105 number_pixels);
4106 if (source_info.storage_class != UndefinedClass)
4107 {
4108 status|=ClonePixelCachePixels(cache_info,&source_info,
4109 exception);
4110 RelinquishPixelCachePixels(&source_info);
4111 }
4112 return(MagickTrue);
4113 }
4114 }
4115 RelinquishMagickResource(MemoryResource,cache_info->length);
4116 }
4117 /*
4118 Create pixel cache on disk.
4119 */
4120 status=AcquireMagickResource(DiskResource,cache_info->length);
4121 if (status == MagickFalse)
4122 {
4123 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4124 "CacheResourcesExhausted","`%s'",image->filename);
4125 return(MagickFalse);
4126 }
4127 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4128 {
4129 RelinquishMagickResource(DiskResource,cache_info->length);
4130 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4131 image->filename);
4132 return(MagickFalse);
4133 }
4134 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4135 cache_info->length);
4136 if (status == MagickFalse)
4137 {
4138 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4139 image->filename);
4140 return(MagickFalse);
4141 }
4142 cache_info->storage_class=image->storage_class;
4143 cache_info->colorspace=image->colorspace;
4144 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4145 status=AcquireMagickResource(AreaResource,cache_info->length);
4146 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4147 cache_info->type=DiskCache;
4148 else
4149 {
4150 status=AcquireMagickResource(MapResource,cache_info->length);
4151 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4152 (cache_info->type != MemoryCache))
4153 cache_info->type=DiskCache;
4154 else
4155 {
4156 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4157 cache_info->offset,(size_t) cache_info->length);
4158 if (cache_info->pixels == (PixelPacket *) NULL)
4159 {
4160 cache_info->pixels=source_info.pixels;
4161 cache_info->type=DiskCache;
4162 }
4163 else
4164 {
4165 /*
4166 Create file-backed memory-mapped pixel cache.
4167 */
4168 (void) ClosePixelCacheOnDisk(cache_info);
4169 cache_info->type=MapCache;
4170 cache_info->mapped=MagickTrue;
4171 cache_info->indexes=(IndexPacket *) NULL;
4172 if (cache_info->active_index_channel != MagickFalse)
4173 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4174 number_pixels);
4175 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4176 {
4177 status=ClonePixelCachePixels(cache_info,&source_info,
4178 exception);
4179 RelinquishPixelCachePixels(&source_info);
4180 }
4181 if (image->debug != MagickFalse)
4182 {
cristy97e7a572009-12-05 15:07:53 +00004183 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004184 format);
cristyb51dff52011-05-19 16:55:47 +00004185 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004186 "open %s (%s[%d], memory-mapped, %.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004187 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004188 cache_info->file,(double) cache_info->columns,(double)
4189 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004190 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4191 message);
4192 }
4193 return(MagickTrue);
4194 }
4195 }
4196 RelinquishMagickResource(MapResource,cache_info->length);
4197 }
4198 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4199 {
4200 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4201 RelinquishPixelCachePixels(&source_info);
4202 }
4203 if (image->debug != MagickFalse)
4204 {
cristyb9080c92009-12-01 20:13:26 +00004205 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004206 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004207 "open %s (%s[%d], disk, %.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004208 cache_info->cache_filename,cache_info->file,(double)
4209 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004210 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4211 }
4212 return(MagickTrue);
4213}
4214
4215/*
4216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4217% %
4218% %
4219% %
4220+ P e r s i s t P i x e l C a c h e %
4221% %
4222% %
4223% %
4224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4225%
4226% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4227% persistent pixel cache is one that resides on disk and is not destroyed
4228% when the program exits.
4229%
4230% The format of the PersistPixelCache() method is:
4231%
4232% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4233% const MagickBooleanType attach,MagickOffsetType *offset,
4234% ExceptionInfo *exception)
4235%
4236% A description of each parameter follows:
4237%
4238% o image: the image.
4239%
4240% o filename: the persistent pixel cache filename.
4241%
cristyf3a6a9d2010-11-07 21:02:56 +00004242% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004243%
cristy3ed852e2009-09-05 21:47:34 +00004244% o initialize: A value other than zero initializes the persistent pixel
4245% cache.
4246%
4247% o offset: the offset in the persistent cache to store pixels.
4248%
4249% o exception: return any errors or warnings in this structure.
4250%
4251*/
4252MagickExport MagickBooleanType PersistPixelCache(Image *image,
4253 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4254 ExceptionInfo *exception)
4255{
4256 CacheInfo
4257 *cache_info,
4258 *clone_info;
4259
4260 Image
4261 clone_image;
4262
cristy3ed852e2009-09-05 21:47:34 +00004263 MagickBooleanType
4264 status;
4265
cristye076a6e2010-08-15 19:59:43 +00004266 ssize_t
4267 page_size;
4268
cristy3ed852e2009-09-05 21:47:34 +00004269 assert(image != (Image *) NULL);
4270 assert(image->signature == MagickSignature);
4271 if (image->debug != MagickFalse)
4272 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4273 assert(image->cache != (void *) NULL);
4274 assert(filename != (const char *) NULL);
4275 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004276 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004277 cache_info=(CacheInfo *) image->cache;
4278 assert(cache_info->signature == MagickSignature);
4279 if (attach != MagickFalse)
4280 {
4281 /*
cristy01b7eb02009-09-10 23:10:14 +00004282 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004283 */
4284 if (image->debug != MagickFalse)
4285 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004286 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004287 (void) CopyMagickString(cache_info->cache_filename,filename,
4288 MaxTextExtent);
4289 cache_info->type=DiskCache;
4290 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004291 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004292 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004293 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004294 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004295 }
cristy01b7eb02009-09-10 23:10:14 +00004296 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4297 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004298 {
cristyf84a1932010-01-03 18:00:18 +00004299 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004300 if ((cache_info->mode != ReadMode) &&
4301 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004302 (cache_info->reference_count == 1))
4303 {
4304 int
4305 status;
4306
4307 /*
cristy01b7eb02009-09-10 23:10:14 +00004308 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004309 */
4310 status=rename(cache_info->cache_filename,filename);
4311 if (status == 0)
4312 {
4313 (void) CopyMagickString(cache_info->cache_filename,filename,
4314 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004315 *offset+=cache_info->length+page_size-(cache_info->length %
4316 page_size);
cristyf84a1932010-01-03 18:00:18 +00004317 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004318 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004319 if (image->debug != MagickFalse)
4320 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4321 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004322 return(MagickTrue);
4323 }
4324 }
cristyf84a1932010-01-03 18:00:18 +00004325 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004326 }
4327 /*
cristy01b7eb02009-09-10 23:10:14 +00004328 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004329 */
4330 clone_image=(*image);
4331 clone_info=(CacheInfo *) clone_image.cache;
4332 image->cache=ClonePixelCache(cache_info);
4333 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4334 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4335 cache_info->type=DiskCache;
4336 cache_info->offset=(*offset);
4337 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004338 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004339 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004340 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004341 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004342 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4343 return(status);
4344}
4345
4346/*
4347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4348% %
4349% %
4350% %
4351+ Q u e u e A u t h e n t i c N e x u s %
4352% %
4353% %
4354% %
4355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4356%
4357% QueueAuthenticNexus() allocates an region to store image pixels as defined
4358% by the region rectangle and returns a pointer to the region. This region is
4359% subsequently transferred from the pixel cache with
4360% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4361% pixels are transferred, otherwise a NULL is returned.
4362%
4363% The format of the QueueAuthenticNexus() method is:
4364%
cristy5f959472010-05-27 22:19:46 +00004365% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4366% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004367% NexusInfo *nexus_info,ExceptionInfo *exception)
4368%
4369% A description of each parameter follows:
4370%
4371% o image: the image.
4372%
4373% o x,y,columns,rows: These values define the perimeter of a region of
4374% pixels.
4375%
4376% o nexus_info: the cache nexus to set.
4377%
4378% o exception: return any errors or warnings in this structure.
4379%
4380*/
cristybb503372010-05-27 20:51:26 +00004381MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004382 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4383 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004384{
4385 CacheInfo
4386 *cache_info;
4387
4388 MagickOffsetType
4389 offset;
4390
4391 MagickSizeType
4392 number_pixels;
4393
4394 RectangleInfo
4395 region;
4396
4397 /*
4398 Validate pixel cache geometry.
4399 */
cristye7cc7cf2010-09-21 13:26:47 +00004400 assert(image != (const Image *) NULL);
4401 assert(image->signature == MagickSignature);
4402 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004403 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004404 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004405 if (cache_info == (Cache) NULL)
4406 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004407 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4408 {
4409 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4410 "NoPixelsDefinedInCache","`%s'",image->filename);
4411 return((PixelPacket *) NULL);
4412 }
cristybb503372010-05-27 20:51:26 +00004413 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4414 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004415 {
4416 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4417 "PixelsAreNotAuthentic","`%s'",image->filename);
4418 return((PixelPacket *) NULL);
4419 }
4420 offset=(MagickOffsetType) y*cache_info->columns+x;
4421 if (offset < 0)
4422 return((PixelPacket *) NULL);
4423 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4424 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4425 if ((MagickSizeType) offset >= number_pixels)
4426 return((PixelPacket *) NULL);
4427 /*
4428 Return pixel cache.
4429 */
4430 region.x=x;
4431 region.y=y;
4432 region.width=columns;
4433 region.height=rows;
4434 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4435}
4436
4437/*
4438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4439% %
4440% %
4441% %
4442+ 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 %
4443% %
4444% %
4445% %
4446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4447%
4448% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4449% defined by the region rectangle and returns a pointer to the region. This
4450% region is subsequently transferred from the pixel cache with
4451% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4452% pixels are transferred, otherwise a NULL is returned.
4453%
4454% The format of the QueueAuthenticPixelsCache() method is:
4455%
cristybb503372010-05-27 20:51:26 +00004456% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4457% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004458% ExceptionInfo *exception)
4459%
4460% A description of each parameter follows:
4461%
4462% o image: the image.
4463%
4464% o x,y,columns,rows: These values define the perimeter of a region of
4465% pixels.
4466%
4467% o exception: return any errors or warnings in this structure.
4468%
4469*/
cristybb503372010-05-27 20:51:26 +00004470static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4471 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004472 ExceptionInfo *exception)
4473{
4474 CacheInfo
4475 *cache_info;
4476
cristy5c9e6f22010-09-17 17:31:01 +00004477 const int
4478 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004479
cristye7cc7cf2010-09-21 13:26:47 +00004480 assert(image != (const Image *) NULL);
4481 assert(image->signature == MagickSignature);
4482 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004483 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004484 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004485 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004486 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4487 exception));
cristy3ed852e2009-09-05 21:47:34 +00004488}
4489
4490/*
4491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4492% %
4493% %
4494% %
4495% Q u e u e A u t h e n t i c P i x e l s %
4496% %
4497% %
4498% %
4499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4500%
4501% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4502% successfully intialized a pointer to a PixelPacket array representing the
4503% region is returned, otherwise NULL is returned. The returned pointer may
4504% point to a temporary working buffer for the pixels or it may point to the
4505% final location of the pixels in memory.
4506%
4507% Write-only access means that any existing pixel values corresponding to
4508% the region are ignored. This is useful if the initial image is being
4509% created from scratch, or if the existing pixel values are to be
4510% completely replaced without need to refer to their pre-existing values.
4511% The application is free to read and write the pixel buffer returned by
4512% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4513% initialize the pixel array values. Initializing pixel array values is the
4514% application's responsibility.
4515%
4516% Performance is maximized if the selected region is part of one row, or
4517% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004518% pixels in-place (without a copy) if the image is in memory, or in a
4519% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004520% by the user.
4521%
4522% Pixels accessed via the returned pointer represent a simple array of type
4523% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4524% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4525% the black color component or the colormap indexes (of type IndexPacket)
4526% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4527% array has been updated, the changes must be saved back to the underlying
4528% image using SyncAuthenticPixels() or they may be lost.
4529%
4530% The format of the QueueAuthenticPixels() method is:
4531%
cristy5f959472010-05-27 22:19:46 +00004532% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4533% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004534% ExceptionInfo *exception)
4535%
4536% A description of each parameter follows:
4537%
4538% o image: the image.
4539%
4540% o x,y,columns,rows: These values define the perimeter of a region of
4541% pixels.
4542%
4543% o exception: return any errors or warnings in this structure.
4544%
4545*/
cristybb503372010-05-27 20:51:26 +00004546MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4547 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004548 ExceptionInfo *exception)
4549{
4550 CacheInfo
4551 *cache_info;
4552
cristy2036f5c2010-09-19 21:18:17 +00004553 const int
4554 id = GetOpenMPThreadId();
4555
cristy3ed852e2009-09-05 21:47:34 +00004556 assert(image != (Image *) NULL);
4557 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004558 assert(image->cache != (Cache) NULL);
4559 cache_info=(CacheInfo *) image->cache;
4560 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004561 if (cache_info->methods.queue_authentic_pixels_handler !=
4562 (QueueAuthenticPixelsHandler) NULL)
4563 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4564 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004565 assert(id < (int) cache_info->number_threads);
4566 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4567 exception));
cristy3ed852e2009-09-05 21:47:34 +00004568}
4569
4570/*
4571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4572% %
4573% %
4574% %
4575+ R e a d P i x e l C a c h e I n d e x e s %
4576% %
4577% %
4578% %
4579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4580%
4581% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4582% the pixel cache.
4583%
4584% The format of the ReadPixelCacheIndexes() method is:
4585%
4586% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4587% NexusInfo *nexus_info,ExceptionInfo *exception)
4588%
4589% A description of each parameter follows:
4590%
4591% o cache_info: the pixel cache.
4592%
4593% o nexus_info: the cache nexus to read the colormap indexes.
4594%
4595% o exception: return any errors or warnings in this structure.
4596%
4597*/
4598static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4599 NexusInfo *nexus_info,ExceptionInfo *exception)
4600{
4601 MagickOffsetType
4602 count,
4603 offset;
4604
4605 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004606 extent,
4607 length;
cristy3ed852e2009-09-05 21:47:34 +00004608
4609 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004610 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004611
cristybb503372010-05-27 20:51:26 +00004612 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004613 y;
4614
cristybb503372010-05-27 20:51:26 +00004615 size_t
cristy3ed852e2009-09-05 21:47:34 +00004616 rows;
4617
cristy3ed852e2009-09-05 21:47:34 +00004618 if (cache_info->active_index_channel == MagickFalse)
4619 return(MagickFalse);
4620 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4621 return(MagickTrue);
4622 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4623 nexus_info->region.x;
4624 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4625 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004626 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004627 q=nexus_info->indexes;
4628 switch (cache_info->type)
4629 {
4630 case MemoryCache:
4631 case MapCache:
4632 {
4633 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004634 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004635
4636 /*
4637 Read indexes from memory.
4638 */
cristydd341db2010-03-04 19:06:38 +00004639 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004640 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004641 {
cristy48078b12010-09-23 17:11:01 +00004642 length=extent;
cristydd341db2010-03-04 19:06:38 +00004643 rows=1UL;
4644 }
cristy3ed852e2009-09-05 21:47:34 +00004645 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004646 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004647 {
cristy8f036fe2010-09-18 02:02:00 +00004648 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004649 p+=cache_info->columns;
4650 q+=nexus_info->region.width;
4651 }
4652 break;
4653 }
4654 case DiskCache:
4655 {
4656 /*
4657 Read indexes from disk.
4658 */
4659 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4660 {
4661 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4662 cache_info->cache_filename);
4663 return(MagickFalse);
4664 }
cristydd341db2010-03-04 19:06:38 +00004665 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004666 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004667 {
cristy48078b12010-09-23 17:11:01 +00004668 length=extent;
cristydd341db2010-03-04 19:06:38 +00004669 rows=1UL;
4670 }
cristy48078b12010-09-23 17:11:01 +00004671 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004672 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004673 {
cristy48078b12010-09-23 17:11:01 +00004674 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristy3ed852e2009-09-05 21:47:34 +00004675 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4676 if ((MagickSizeType) count < length)
4677 break;
4678 offset+=cache_info->columns;
4679 q+=nexus_info->region.width;
4680 }
cristybb503372010-05-27 20:51:26 +00004681 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004682 {
4683 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4684 cache_info->cache_filename);
4685 return(MagickFalse);
4686 }
4687 break;
4688 }
4689 default:
4690 break;
4691 }
4692 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004693 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004694 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004695 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004696 nexus_info->region.width,(double) nexus_info->region.height,(double)
4697 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004698 return(MagickTrue);
4699}
4700
4701/*
4702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703% %
4704% %
4705% %
4706+ R e a d P i x e l C a c h e P i x e l s %
4707% %
4708% %
4709% %
4710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4711%
4712% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4713% cache.
4714%
4715% The format of the ReadPixelCachePixels() method is:
4716%
4717% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4718% NexusInfo *nexus_info,ExceptionInfo *exception)
4719%
4720% A description of each parameter follows:
4721%
4722% o cache_info: the pixel cache.
4723%
4724% o nexus_info: the cache nexus to read the pixels.
4725%
4726% o exception: return any errors or warnings in this structure.
4727%
4728*/
4729static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4730 NexusInfo *nexus_info,ExceptionInfo *exception)
4731{
4732 MagickOffsetType
4733 count,
4734 offset;
4735
4736 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004737 extent,
4738 length;
cristy3ed852e2009-09-05 21:47:34 +00004739
cristy3ed852e2009-09-05 21:47:34 +00004740 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004741 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004742
cristye076a6e2010-08-15 19:59:43 +00004743 register ssize_t
4744 y;
4745
cristybb503372010-05-27 20:51:26 +00004746 size_t
cristy3ed852e2009-09-05 21:47:34 +00004747 rows;
4748
cristy3ed852e2009-09-05 21:47:34 +00004749 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4750 return(MagickTrue);
4751 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4752 nexus_info->region.x;
4753 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4754 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004755 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004756 q=nexus_info->pixels;
4757 switch (cache_info->type)
4758 {
4759 case MemoryCache:
4760 case MapCache:
4761 {
4762 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004763 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004764
4765 /*
4766 Read pixels from memory.
4767 */
cristydd341db2010-03-04 19:06:38 +00004768 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004769 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004770 {
cristy48078b12010-09-23 17:11:01 +00004771 length=extent;
cristydd341db2010-03-04 19:06:38 +00004772 rows=1UL;
4773 }
cristy3ed852e2009-09-05 21:47:34 +00004774 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004775 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004776 {
cristy8f036fe2010-09-18 02:02:00 +00004777 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004778 p+=cache_info->columns;
4779 q+=nexus_info->region.width;
4780 }
4781 break;
4782 }
4783 case DiskCache:
4784 {
4785 /*
4786 Read pixels from disk.
4787 */
4788 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4789 {
4790 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4791 cache_info->cache_filename);
4792 return(MagickFalse);
4793 }
cristydd341db2010-03-04 19:06:38 +00004794 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004795 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004796 {
cristy48078b12010-09-23 17:11:01 +00004797 length=extent;
cristydd341db2010-03-04 19:06:38 +00004798 rows=1UL;
4799 }
cristybb503372010-05-27 20:51:26 +00004800 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004801 {
4802 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4803 sizeof(*q),length,(unsigned char *) q);
4804 if ((MagickSizeType) count < length)
4805 break;
4806 offset+=cache_info->columns;
4807 q+=nexus_info->region.width;
4808 }
cristybb503372010-05-27 20:51:26 +00004809 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004810 {
4811 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4812 cache_info->cache_filename);
4813 return(MagickFalse);
4814 }
4815 break;
4816 }
4817 default:
4818 break;
4819 }
4820 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004821 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004822 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004823 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004824 nexus_info->region.width,(double) nexus_info->region.height,(double)
4825 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004826 return(MagickTrue);
4827}
4828
4829/*
4830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4831% %
4832% %
4833% %
4834+ R e f e r e n c e P i x e l C a c h e %
4835% %
4836% %
4837% %
4838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4839%
4840% ReferencePixelCache() increments the reference count associated with the
4841% pixel cache returning a pointer to the cache.
4842%
4843% The format of the ReferencePixelCache method is:
4844%
4845% Cache ReferencePixelCache(Cache cache_info)
4846%
4847% A description of each parameter follows:
4848%
4849% o cache_info: the pixel cache.
4850%
4851*/
4852MagickExport Cache ReferencePixelCache(Cache cache)
4853{
4854 CacheInfo
4855 *cache_info;
4856
4857 assert(cache != (Cache *) NULL);
4858 cache_info=(CacheInfo *) cache;
4859 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004860 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004861 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004862 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004863 return(cache_info);
4864}
4865
4866/*
4867%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4868% %
4869% %
4870% %
4871+ S e t P i x e l C a c h e M e t h o d s %
4872% %
4873% %
4874% %
4875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4876%
4877% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4878%
4879% The format of the SetPixelCacheMethods() method is:
4880%
4881% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4882%
4883% A description of each parameter follows:
4884%
4885% o cache: the pixel cache.
4886%
4887% o cache_methods: Specifies a pointer to a CacheMethods structure.
4888%
4889*/
4890MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4891{
4892 CacheInfo
4893 *cache_info;
4894
4895 GetOneAuthenticPixelFromHandler
4896 get_one_authentic_pixel_from_handler;
4897
4898 GetOneVirtualPixelFromHandler
4899 get_one_virtual_pixel_from_handler;
4900
4901 /*
4902 Set cache pixel methods.
4903 */
4904 assert(cache != (Cache) NULL);
4905 assert(cache_methods != (CacheMethods *) NULL);
4906 cache_info=(CacheInfo *) cache;
4907 assert(cache_info->signature == MagickSignature);
4908 if (cache_info->debug != MagickFalse)
4909 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4910 cache_info->filename);
4911 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4912 cache_info->methods.get_virtual_pixel_handler=
4913 cache_methods->get_virtual_pixel_handler;
4914 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4915 cache_info->methods.destroy_pixel_handler=
4916 cache_methods->destroy_pixel_handler;
4917 if (cache_methods->get_virtual_indexes_from_handler !=
4918 (GetVirtualIndexesFromHandler) NULL)
4919 cache_info->methods.get_virtual_indexes_from_handler=
4920 cache_methods->get_virtual_indexes_from_handler;
4921 if (cache_methods->get_authentic_pixels_handler !=
4922 (GetAuthenticPixelsHandler) NULL)
4923 cache_info->methods.get_authentic_pixels_handler=
4924 cache_methods->get_authentic_pixels_handler;
4925 if (cache_methods->queue_authentic_pixels_handler !=
4926 (QueueAuthenticPixelsHandler) NULL)
4927 cache_info->methods.queue_authentic_pixels_handler=
4928 cache_methods->queue_authentic_pixels_handler;
4929 if (cache_methods->sync_authentic_pixels_handler !=
4930 (SyncAuthenticPixelsHandler) NULL)
4931 cache_info->methods.sync_authentic_pixels_handler=
4932 cache_methods->sync_authentic_pixels_handler;
4933 if (cache_methods->get_authentic_pixels_from_handler !=
4934 (GetAuthenticPixelsFromHandler) NULL)
4935 cache_info->methods.get_authentic_pixels_from_handler=
4936 cache_methods->get_authentic_pixels_from_handler;
4937 if (cache_methods->get_authentic_indexes_from_handler !=
4938 (GetAuthenticIndexesFromHandler) NULL)
4939 cache_info->methods.get_authentic_indexes_from_handler=
4940 cache_methods->get_authentic_indexes_from_handler;
4941 get_one_virtual_pixel_from_handler=
4942 cache_info->methods.get_one_virtual_pixel_from_handler;
4943 if (get_one_virtual_pixel_from_handler !=
4944 (GetOneVirtualPixelFromHandler) NULL)
4945 cache_info->methods.get_one_virtual_pixel_from_handler=
4946 cache_methods->get_one_virtual_pixel_from_handler;
4947 get_one_authentic_pixel_from_handler=
4948 cache_methods->get_one_authentic_pixel_from_handler;
4949 if (get_one_authentic_pixel_from_handler !=
4950 (GetOneAuthenticPixelFromHandler) NULL)
4951 cache_info->methods.get_one_authentic_pixel_from_handler=
4952 cache_methods->get_one_authentic_pixel_from_handler;
4953}
4954
4955/*
4956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4957% %
4958% %
4959% %
4960+ S e t P i x e l C a c h e N e x u s P i x e l s %
4961% %
4962% %
4963% %
4964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4965%
4966% SetPixelCacheNexusPixels() defines the region of the cache for the
4967% specified cache nexus.
4968%
4969% The format of the SetPixelCacheNexusPixels() method is:
4970%
4971% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4972% const RectangleInfo *region,NexusInfo *nexus_info,
4973% ExceptionInfo *exception)
4974%
4975% A description of each parameter follows:
4976%
4977% o image: the image.
4978%
4979% o region: A pointer to the RectangleInfo structure that defines the
4980% region of this particular cache nexus.
4981%
4982% o nexus_info: the cache nexus to set.
4983%
4984% o exception: return any errors or warnings in this structure.
4985%
4986*/
cristyabd6e372010-09-15 19:11:26 +00004987
4988static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4989 NexusInfo *nexus_info,ExceptionInfo *exception)
4990{
4991 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4992 return(MagickFalse);
4993 nexus_info->mapped=MagickFalse;
4994 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4995 nexus_info->length);
4996 if (nexus_info->cache == (PixelPacket *) NULL)
4997 {
4998 nexus_info->mapped=MagickTrue;
4999 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
5000 nexus_info->length);
5001 }
5002 if (nexus_info->cache == (PixelPacket *) NULL)
5003 {
5004 (void) ThrowMagickException(exception,GetMagickModule(),
5005 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5006 cache_info->filename);
5007 return(MagickFalse);
5008 }
5009 return(MagickTrue);
5010}
5011
cristy3ed852e2009-09-05 21:47:34 +00005012static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5013 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5014{
5015 CacheInfo
5016 *cache_info;
5017
5018 MagickBooleanType
5019 status;
5020
cristy3ed852e2009-09-05 21:47:34 +00005021 MagickSizeType
5022 length,
5023 number_pixels;
5024
cristy3ed852e2009-09-05 21:47:34 +00005025 cache_info=(CacheInfo *) image->cache;
5026 assert(cache_info->signature == MagickSignature);
5027 if (cache_info->type == UndefinedCache)
5028 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005029 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005030 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5031 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005032 {
cristybb503372010-05-27 20:51:26 +00005033 ssize_t
cristybad067a2010-02-15 17:20:55 +00005034 x,
5035 y;
cristy3ed852e2009-09-05 21:47:34 +00005036
cristyeaedf062010-05-29 22:36:02 +00005037 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5038 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005039 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5040 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005041 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005042 ((nexus_info->region.width == cache_info->columns) ||
5043 ((nexus_info->region.width % cache_info->columns) == 0)))))
5044 {
5045 MagickOffsetType
5046 offset;
5047
5048 /*
5049 Pixels are accessed directly from memory.
5050 */
5051 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5052 nexus_info->region.x;
5053 nexus_info->pixels=cache_info->pixels+offset;
5054 nexus_info->indexes=(IndexPacket *) NULL;
5055 if (cache_info->active_index_channel != MagickFalse)
5056 nexus_info->indexes=cache_info->indexes+offset;
5057 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005058 }
5059 }
5060 /*
5061 Pixels are stored in a cache region until they are synced to the cache.
5062 */
5063 number_pixels=(MagickSizeType) nexus_info->region.width*
5064 nexus_info->region.height;
5065 length=number_pixels*sizeof(PixelPacket);
5066 if (cache_info->active_index_channel != MagickFalse)
5067 length+=number_pixels*sizeof(IndexPacket);
5068 if (nexus_info->cache == (PixelPacket *) NULL)
5069 {
5070 nexus_info->length=length;
5071 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5072 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005073 {
5074 nexus_info->length=0;
5075 return((PixelPacket *) NULL);
5076 }
cristy3ed852e2009-09-05 21:47:34 +00005077 }
5078 else
5079 if (nexus_info->length != length)
5080 {
5081 RelinquishCacheNexusPixels(nexus_info);
5082 nexus_info->length=length;
5083 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5084 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005085 {
5086 nexus_info->length=0;
5087 return((PixelPacket *) NULL);
5088 }
cristy3ed852e2009-09-05 21:47:34 +00005089 }
5090 nexus_info->pixels=nexus_info->cache;
5091 nexus_info->indexes=(IndexPacket *) NULL;
5092 if (cache_info->active_index_channel != MagickFalse)
5093 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5094 return(nexus_info->pixels);
5095}
5096
5097/*
5098%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5099% %
5100% %
5101% %
5102% 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 %
5103% %
5104% %
5105% %
5106%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5107%
5108% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5109% pixel cache and returns the previous setting. A virtual pixel is any pixel
5110% access that is outside the boundaries of the image cache.
5111%
5112% The format of the SetPixelCacheVirtualMethod() method is:
5113%
5114% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5115% const VirtualPixelMethod virtual_pixel_method)
5116%
5117% A description of each parameter follows:
5118%
5119% o image: the image.
5120%
5121% o virtual_pixel_method: choose the type of virtual pixel.
5122%
5123*/
5124MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5125 const VirtualPixelMethod virtual_pixel_method)
5126{
5127 CacheInfo
5128 *cache_info;
5129
5130 VirtualPixelMethod
5131 method;
5132
5133 assert(image != (Image *) NULL);
5134 assert(image->signature == MagickSignature);
5135 if (image->debug != MagickFalse)
5136 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5137 assert(image->cache != (Cache) NULL);
5138 cache_info=(CacheInfo *) image->cache;
5139 assert(cache_info->signature == MagickSignature);
5140 method=cache_info->virtual_pixel_method;
5141 cache_info->virtual_pixel_method=virtual_pixel_method;
5142 return(method);
5143}
5144
5145/*
5146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5147% %
5148% %
5149% %
5150+ 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 %
5151% %
5152% %
5153% %
5154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5155%
5156% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5157% in-memory or disk cache. The method returns MagickTrue if the pixel region
5158% is synced, otherwise MagickFalse.
5159%
5160% The format of the SyncAuthenticPixelCacheNexus() method is:
5161%
5162% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5163% NexusInfo *nexus_info,ExceptionInfo *exception)
5164%
5165% A description of each parameter follows:
5166%
5167% o image: the image.
5168%
5169% o nexus_info: the cache nexus to sync.
5170%
5171% o exception: return any errors or warnings in this structure.
5172%
5173*/
5174MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5175 NexusInfo *nexus_info,ExceptionInfo *exception)
5176{
5177 CacheInfo
5178 *cache_info;
5179
5180 MagickBooleanType
5181 status;
5182
5183 /*
5184 Transfer pixels to the cache.
5185 */
5186 assert(image != (Image *) NULL);
5187 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005188 if (image->cache == (Cache) NULL)
5189 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5190 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005191 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005192 if (cache_info->type == UndefinedCache)
5193 return(MagickFalse);
5194 if ((image->clip_mask != (Image *) NULL) &&
5195 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5196 return(MagickFalse);
5197 if ((image->mask != (Image *) NULL) &&
5198 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5199 return(MagickFalse);
5200 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5201 return(MagickTrue);
5202 assert(cache_info->signature == MagickSignature);
5203 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5204 if ((cache_info->active_index_channel != MagickFalse) &&
5205 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5206 return(MagickFalse);
5207 return(status);
5208}
5209
5210/*
5211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5212% %
5213% %
5214% %
5215+ S y n c A u t h e n t i c P i x e l C a c h e %
5216% %
5217% %
5218% %
5219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5220%
5221% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5222% or disk cache. The method returns MagickTrue if the pixel region is synced,
5223% otherwise MagickFalse.
5224%
5225% The format of the SyncAuthenticPixelsCache() method is:
5226%
5227% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5228% ExceptionInfo *exception)
5229%
5230% A description of each parameter follows:
5231%
5232% o image: the image.
5233%
5234% o exception: return any errors or warnings in this structure.
5235%
5236*/
5237static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5238 ExceptionInfo *exception)
5239{
5240 CacheInfo
5241 *cache_info;
5242
cristy5c9e6f22010-09-17 17:31:01 +00005243 const int
5244 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005245
cristye7cc7cf2010-09-21 13:26:47 +00005246 assert(image != (Image *) NULL);
5247 assert(image->signature == MagickSignature);
5248 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005249 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005250 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005251 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005252 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5253 exception));
cristy3ed852e2009-09-05 21:47:34 +00005254}
5255
5256/*
5257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5258% %
5259% %
5260% %
5261% S y n c A u t h e n t i c P i x e l s %
5262% %
5263% %
5264% %
5265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5266%
5267% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5268% The method returns MagickTrue if the pixel region is flushed, otherwise
5269% MagickFalse.
5270%
5271% The format of the SyncAuthenticPixels() method is:
5272%
5273% MagickBooleanType SyncAuthenticPixels(Image *image,
5274% ExceptionInfo *exception)
5275%
5276% A description of each parameter follows:
5277%
5278% o image: the image.
5279%
5280% o exception: return any errors or warnings in this structure.
5281%
5282*/
5283MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5284 ExceptionInfo *exception)
5285{
5286 CacheInfo
5287 *cache_info;
5288
cristy2036f5c2010-09-19 21:18:17 +00005289 const int
5290 id = GetOpenMPThreadId();
5291
cristy3ed852e2009-09-05 21:47:34 +00005292 assert(image != (Image *) NULL);
5293 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005294 assert(image->cache != (Cache) NULL);
5295 cache_info=(CacheInfo *) image->cache;
5296 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005297 if (cache_info->methods.sync_authentic_pixels_handler !=
5298 (SyncAuthenticPixelsHandler) NULL)
5299 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005300 assert(id < (int) cache_info->number_threads);
5301 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5302 exception));
cristy3ed852e2009-09-05 21:47:34 +00005303}
5304
5305/*
5306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5307% %
5308% %
5309% %
5310+ W r i t e P i x e l C a c h e I n d e x e s %
5311% %
5312% %
5313% %
5314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5315%
5316% WritePixelCacheIndexes() writes the colormap indexes to the specified
5317% region of the pixel cache.
5318%
5319% The format of the WritePixelCacheIndexes() method is:
5320%
5321% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5322% NexusInfo *nexus_info,ExceptionInfo *exception)
5323%
5324% A description of each parameter follows:
5325%
5326% o cache_info: the pixel cache.
5327%
5328% o nexus_info: the cache nexus to write the colormap indexes.
5329%
5330% o exception: return any errors or warnings in this structure.
5331%
5332*/
5333static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5334 NexusInfo *nexus_info,ExceptionInfo *exception)
5335{
5336 MagickOffsetType
5337 count,
5338 offset;
5339
5340 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005341 extent,
5342 length;
cristy3ed852e2009-09-05 21:47:34 +00005343
5344 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005345 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005346
cristybb503372010-05-27 20:51:26 +00005347 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005348 y;
5349
cristybb503372010-05-27 20:51:26 +00005350 size_t
cristy3ed852e2009-09-05 21:47:34 +00005351 rows;
5352
cristy3ed852e2009-09-05 21:47:34 +00005353 if (cache_info->active_index_channel == MagickFalse)
5354 return(MagickFalse);
5355 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5356 return(MagickTrue);
5357 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5358 nexus_info->region.x;
5359 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5360 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005361 extent=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005362 p=nexus_info->indexes;
5363 switch (cache_info->type)
5364 {
5365 case MemoryCache:
5366 case MapCache:
5367 {
5368 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005369 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005370
5371 /*
5372 Write indexes to memory.
5373 */
cristydd341db2010-03-04 19:06:38 +00005374 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005375 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005376 {
cristy48078b12010-09-23 17:11:01 +00005377 length=extent;
cristydd341db2010-03-04 19:06:38 +00005378 rows=1UL;
5379 }
cristy3ed852e2009-09-05 21:47:34 +00005380 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005381 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005382 {
cristy8f036fe2010-09-18 02:02:00 +00005383 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005384 p+=nexus_info->region.width;
5385 q+=cache_info->columns;
5386 }
5387 break;
5388 }
5389 case DiskCache:
5390 {
5391 /*
5392 Write indexes to disk.
5393 */
5394 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5395 {
5396 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5397 cache_info->cache_filename);
5398 return(MagickFalse);
5399 }
cristydd341db2010-03-04 19:06:38 +00005400 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005401 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005402 {
cristy48078b12010-09-23 17:11:01 +00005403 length=extent;
cristydd341db2010-03-04 19:06:38 +00005404 rows=1UL;
5405 }
cristy48078b12010-09-23 17:11:01 +00005406 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005407 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005408 {
cristy48078b12010-09-23 17:11:01 +00005409 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5410 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5411 p);
cristy3ed852e2009-09-05 21:47:34 +00005412 if ((MagickSizeType) count < length)
5413 break;
5414 p+=nexus_info->region.width;
5415 offset+=cache_info->columns;
5416 }
cristybb503372010-05-27 20:51:26 +00005417 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005418 {
5419 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5420 cache_info->cache_filename);
5421 return(MagickFalse);
5422 }
5423 break;
5424 }
5425 default:
5426 break;
5427 }
5428 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005429 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005430 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005431 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005432 nexus_info->region.width,(double) nexus_info->region.height,(double)
5433 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005434 return(MagickTrue);
5435}
5436
5437/*
5438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5439% %
5440% %
5441% %
5442+ W r i t e C a c h e P i x e l s %
5443% %
5444% %
5445% %
5446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5447%
5448% WritePixelCachePixels() writes image pixels to the specified region of the
5449% pixel cache.
5450%
5451% The format of the WritePixelCachePixels() method is:
5452%
5453% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5454% NexusInfo *nexus_info,ExceptionInfo *exception)
5455%
5456% A description of each parameter follows:
5457%
5458% o cache_info: the pixel cache.
5459%
5460% o nexus_info: the cache nexus to write the pixels.
5461%
5462% o exception: return any errors or warnings in this structure.
5463%
5464*/
5465static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5466 NexusInfo *nexus_info,ExceptionInfo *exception)
5467{
5468 MagickOffsetType
5469 count,
5470 offset;
5471
5472 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005473 extent,
5474 length;
cristy3ed852e2009-09-05 21:47:34 +00005475
cristy3ed852e2009-09-05 21:47:34 +00005476 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005477 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005478
cristybb503372010-05-27 20:51:26 +00005479 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005480 y;
5481
cristybb503372010-05-27 20:51:26 +00005482 size_t
cristy3ed852e2009-09-05 21:47:34 +00005483 rows;
5484
cristy3ed852e2009-09-05 21:47:34 +00005485 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5486 return(MagickTrue);
5487 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5488 nexus_info->region.x;
5489 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5490 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005491 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005492 p=nexus_info->pixels;
5493 switch (cache_info->type)
5494 {
5495 case MemoryCache:
5496 case MapCache:
5497 {
5498 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005499 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005500
5501 /*
5502 Write pixels to memory.
5503 */
cristydd341db2010-03-04 19:06:38 +00005504 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005505 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005506 {
cristy48078b12010-09-23 17:11:01 +00005507 length=extent;
cristydd341db2010-03-04 19:06:38 +00005508 rows=1UL;
5509 }
cristy3ed852e2009-09-05 21:47:34 +00005510 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005511 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005512 {
cristy8f036fe2010-09-18 02:02:00 +00005513 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005514 p+=nexus_info->region.width;
5515 q+=cache_info->columns;
5516 }
5517 break;
5518 }
5519 case DiskCache:
5520 {
5521 /*
5522 Write pixels to disk.
5523 */
5524 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5525 {
5526 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5527 cache_info->cache_filename);
5528 return(MagickFalse);
5529 }
cristydd341db2010-03-04 19:06:38 +00005530 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005531 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005532 {
cristy48078b12010-09-23 17:11:01 +00005533 length=extent;
cristydd341db2010-03-04 19:06:38 +00005534 rows=1UL;
5535 }
cristybb503372010-05-27 20:51:26 +00005536 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005537 {
5538 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5539 sizeof(*p),length,(const unsigned char *) p);
5540 if ((MagickSizeType) count < length)
5541 break;
5542 p+=nexus_info->region.width;
5543 offset+=cache_info->columns;
5544 }
cristybb503372010-05-27 20:51:26 +00005545 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005546 {
5547 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5548 cache_info->cache_filename);
5549 return(MagickFalse);
5550 }
5551 break;
5552 }
5553 default:
5554 break;
5555 }
5556 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005557 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005558 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005559 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005560 nexus_info->region.width,(double) nexus_info->region.height,(double)
5561 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005562 return(MagickTrue);
5563}