blob: 9d228a8ccc6998a1d52248f045cc8d3acad1b10e [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 {
cristyce70c172010-01-07 17:15:30 +0000463 SetRedPixelComponent(q,GetRedPixelComponent(p));
464 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
465 SetBluePixelComponent(q,GetBluePixelComponent(p));
466 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000467 if (cache_info->active_index_channel != MagickFalse)
cristyc8d25bc2011-04-29 02:19:30 +0000468 SetIndexPixelComponent(nexus_indexes+i,GetIndexPixelComponent(
469 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
1502 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1503 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 *pixel=image->background_color;
2206 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2207 if (pixels == (PixelPacket *) NULL)
2208 return(MagickFalse);
2209 *pixel=(*pixels);
2210 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002211}
2212
2213/*
2214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215% %
2216% %
2217% %
2218+ 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 %
2219% %
2220% %
2221% %
2222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2223%
2224% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2225% location. The image background color is returned if an error occurs.
2226%
2227% The format of the GetOneAuthenticPixelFromCache() method is:
2228%
2229% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002230% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2231% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002232%
2233% A description of each parameter follows:
2234%
2235% o image: the image.
2236%
2237% o x,y: These values define the location of the pixel to return.
2238%
2239% o pixel: return a pixel at the specified (x,y) location.
2240%
2241% o exception: return any errors or warnings in this structure.
2242%
2243*/
2244static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002245 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002246{
cristy098f78c2010-09-23 17:28:44 +00002247 CacheInfo
2248 *cache_info;
2249
2250 const int
2251 id = GetOpenMPThreadId();
2252
cristy3ed852e2009-09-05 21:47:34 +00002253 PixelPacket
2254 *pixels;
2255
cristy0158a4b2010-09-20 13:59:45 +00002256 assert(image != (const Image *) NULL);
2257 assert(image->signature == MagickSignature);
2258 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002259 cache_info=(CacheInfo *) image->cache;
2260 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002261 *pixel=image->background_color;
cristy098f78c2010-09-23 17:28:44 +00002262 assert(id < (int) cache_info->number_threads);
2263 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2264 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002265 if (pixels == (PixelPacket *) NULL)
2266 return(MagickFalse);
2267 *pixel=(*pixels);
2268 return(MagickTrue);
2269}
2270
2271/*
2272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273% %
2274% %
2275% %
2276% G e t O n e V i r t u a l M a g i c k P i x e l %
2277% %
2278% %
2279% %
2280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281%
2282% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2283% location. The image background color is returned if an error occurs. If
2284% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2285%
2286% The format of the GetOneVirtualMagickPixel() method is:
2287%
2288% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002289% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002290% ExceptionInfo exception)
2291%
2292% A description of each parameter follows:
2293%
2294% o image: the image.
2295%
2296% o x,y: these values define the location of the pixel to return.
2297%
2298% o pixel: return a pixel at the specified (x,y) location.
2299%
2300% o exception: return any errors or warnings in this structure.
2301%
2302*/
2303MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002304 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2305 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002306{
2307 CacheInfo
2308 *cache_info;
2309
cristy0158a4b2010-09-20 13:59:45 +00002310 const int
2311 id = GetOpenMPThreadId();
2312
cristy3ed852e2009-09-05 21:47:34 +00002313 register const IndexPacket
2314 *indexes;
2315
2316 register const PixelPacket
cristy0158a4b2010-09-20 13:59:45 +00002317 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002318
2319 assert(image != (const Image *) NULL);
2320 assert(image->signature == MagickSignature);
2321 assert(image->cache != (Cache) NULL);
2322 cache_info=(CacheInfo *) image->cache;
2323 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002324 assert(id < (int) cache_info->number_threads);
2325 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2326 1UL,1UL,cache_info->nexus_info[id],exception);
cristye7cc7cf2010-09-21 13:26:47 +00002327 GetMagickPixelPacket(image,pixel);
cristy0158a4b2010-09-20 13:59:45 +00002328 if (pixels == (const PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002329 return(MagickFalse);
cristy098f78c2010-09-23 17:28:44 +00002330 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
cristy0158a4b2010-09-20 13:59:45 +00002331 SetMagickPixelPacket(image,pixels,indexes,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002332 return(MagickTrue);
2333}
2334
2335/*
2336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337% %
2338% %
2339% %
2340% G e t O n e V i r t u a l M e t h o d P i x e l %
2341% %
2342% %
2343% %
2344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2345%
2346% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2347% location as defined by specified pixel method. The image background color
2348% is returned if an error occurs. If you plan to modify the pixel, use
2349% GetOneAuthenticPixel() instead.
2350%
2351% The format of the GetOneVirtualMethodPixel() method is:
2352%
2353% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002354% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2355% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002356%
2357% A description of each parameter follows:
2358%
2359% o image: the image.
2360%
2361% o virtual_pixel_method: the virtual pixel method.
2362%
2363% o x,y: These values define the location of the pixel to return.
2364%
2365% o pixel: return a pixel at the specified (x,y) location.
2366%
2367% o exception: return any errors or warnings in this structure.
2368%
2369*/
2370MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002371 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002372 PixelPacket *pixel,ExceptionInfo *exception)
2373{
cristy3ed852e2009-09-05 21:47:34 +00002374 CacheInfo
2375 *cache_info;
2376
cristy0158a4b2010-09-20 13:59:45 +00002377 const int
2378 id = GetOpenMPThreadId();
2379
cristy2036f5c2010-09-19 21:18:17 +00002380 const PixelPacket
2381 *pixels;
2382
cristy3ed852e2009-09-05 21:47:34 +00002383 assert(image != (const Image *) NULL);
2384 assert(image->signature == MagickSignature);
2385 assert(image->cache != (Cache) NULL);
2386 cache_info=(CacheInfo *) image->cache;
2387 assert(cache_info->signature == MagickSignature);
2388 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002389 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2390 (GetOneVirtualPixelFromHandler) NULL)
2391 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2392 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002393 assert(id < (int) cache_info->number_threads);
2394 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2395 cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002396 if (pixels == (const PixelPacket *) NULL)
2397 return(MagickFalse);
2398 *pixel=(*pixels);
2399 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002400}
2401
2402/*
2403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2404% %
2405% %
2406% %
2407% G e t O n e V i r t u a l P i x e l %
2408% %
2409% %
2410% %
2411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2412%
2413% GetOneVirtualPixel() returns a single virtual pixel at the specified
2414% (x,y) location. The image background color is returned if an error occurs.
2415% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2416%
2417% The format of the GetOneVirtualPixel() method is:
2418%
cristybb503372010-05-27 20:51:26 +00002419% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2420% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002421%
2422% A description of each parameter follows:
2423%
2424% o image: the image.
2425%
2426% o x,y: These values define the location of the pixel to return.
2427%
2428% o pixel: return a pixel at the specified (x,y) location.
2429%
2430% o exception: return any errors or warnings in this structure.
2431%
2432*/
2433MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002434 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002435{
cristy3ed852e2009-09-05 21:47:34 +00002436 CacheInfo
2437 *cache_info;
2438
cristy0158a4b2010-09-20 13:59:45 +00002439 const int
2440 id = GetOpenMPThreadId();
2441
cristy2036f5c2010-09-19 21:18:17 +00002442 const PixelPacket
2443 *pixels;
2444
cristy3ed852e2009-09-05 21:47:34 +00002445 assert(image != (const Image *) NULL);
2446 assert(image->signature == MagickSignature);
2447 assert(image->cache != (Cache) NULL);
2448 cache_info=(CacheInfo *) image->cache;
2449 assert(cache_info->signature == MagickSignature);
2450 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002451 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2452 (GetOneVirtualPixelFromHandler) NULL)
2453 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2454 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002455 assert(id < (int) cache_info->number_threads);
2456 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2457 1UL,1UL,cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002458 if (pixels == (const PixelPacket *) NULL)
2459 return(MagickFalse);
2460 *pixel=(*pixels);
2461 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002462}
2463
2464/*
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466% %
2467% %
2468% %
2469+ 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 %
2470% %
2471% %
2472% %
2473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474%
2475% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2476% specified (x,y) location. The image background color is returned if an
2477% error occurs.
2478%
2479% The format of the GetOneVirtualPixelFromCache() method is:
2480%
2481% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002482% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002483% PixelPacket *pixel,ExceptionInfo *exception)
2484%
2485% A description of each parameter follows:
2486%
2487% o image: the image.
2488%
2489% o virtual_pixel_method: the virtual pixel method.
2490%
2491% o x,y: These values define the location of the pixel to return.
2492%
2493% o pixel: return a pixel at the specified (x,y) location.
2494%
2495% o exception: return any errors or warnings in this structure.
2496%
2497*/
2498static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002499 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002500 PixelPacket *pixel,ExceptionInfo *exception)
2501{
cristy0158a4b2010-09-20 13:59:45 +00002502 CacheInfo
2503 *cache_info;
2504
2505 const int
2506 id = GetOpenMPThreadId();
2507
cristy3ed852e2009-09-05 21:47:34 +00002508 const PixelPacket
2509 *pixels;
2510
cristye7cc7cf2010-09-21 13:26:47 +00002511 assert(image != (const Image *) NULL);
2512 assert(image->signature == MagickSignature);
2513 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002514 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002515 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002516 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002517 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002518 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2519 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002520 if (pixels == (const PixelPacket *) NULL)
2521 return(MagickFalse);
2522 *pixel=(*pixels);
2523 return(MagickTrue);
2524}
2525
2526/*
2527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2528% %
2529% %
2530% %
cristy0d267172011-04-25 20:13:48 +00002531+ G e t P i x e l C a c h e C h a n n e l s %
2532% %
2533% %
2534% %
2535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2536%
2537% GetPixelCacheChannels() returns the number of pixel channels associated
2538% with this instance of the pixel cache.
2539%
2540% The format of the GetPixelCacheChannels() method is:
2541%
2542% size_t GetPixelCacheChannels(Cache cache)
2543%
2544% A description of each parameter follows:
2545%
2546% o type: GetPixelCacheChannels returns DirectClass or PseudoClass.
2547%
2548% o cache: the pixel cache.
2549%
2550*/
2551MagickExport size_t GetPixelCacheChannels(const Cache cache)
2552{
2553 CacheInfo
2554 *cache_info;
2555
2556 assert(cache != (Cache) NULL);
2557 cache_info=(CacheInfo *) cache;
2558 assert(cache_info->signature == MagickSignature);
2559 if (cache_info->debug != MagickFalse)
2560 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2561 cache_info->filename);
2562 return(cache_info->channels);
2563}
2564
2565/*
2566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2567% %
2568% %
2569% %
cristy3ed852e2009-09-05 21:47:34 +00002570+ G e t P i x e l C a c h e C o l o r s p a c e %
2571% %
2572% %
2573% %
2574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2575%
2576% GetPixelCacheColorspace() returns the class type of the pixel cache.
2577%
2578% The format of the GetPixelCacheColorspace() method is:
2579%
2580% Colorspace GetPixelCacheColorspace(Cache cache)
2581%
2582% A description of each parameter follows:
2583%
2584% o cache: the pixel cache.
2585%
2586*/
2587MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2588{
2589 CacheInfo
2590 *cache_info;
2591
2592 assert(cache != (Cache) NULL);
2593 cache_info=(CacheInfo *) cache;
2594 assert(cache_info->signature == MagickSignature);
2595 if (cache_info->debug != MagickFalse)
2596 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2597 cache_info->filename);
2598 return(cache_info->colorspace);
2599}
2600
2601/*
2602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2603% %
2604% %
2605% %
2606+ G e t P i x e l C a c h e M e t h o d s %
2607% %
2608% %
2609% %
2610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2611%
2612% GetPixelCacheMethods() initializes the CacheMethods structure.
2613%
2614% The format of the GetPixelCacheMethods() method is:
2615%
2616% void GetPixelCacheMethods(CacheMethods *cache_methods)
2617%
2618% A description of each parameter follows:
2619%
2620% o cache_methods: Specifies a pointer to a CacheMethods structure.
2621%
2622*/
2623MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2624{
2625 assert(cache_methods != (CacheMethods *) NULL);
2626 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2627 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2628 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2629 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2630 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2631 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2632 cache_methods->get_authentic_indexes_from_handler=
2633 GetAuthenticIndexesFromCache;
2634 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2635 cache_methods->get_one_authentic_pixel_from_handler=
2636 GetOneAuthenticPixelFromCache;
2637 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2638 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2639 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2640}
2641
2642/*
2643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2644% %
2645% %
2646% %
2647+ G e t P i x e l C a c h e N e x u s E x t e n t %
2648% %
2649% %
2650% %
2651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2652%
2653% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2654% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2655%
2656% The format of the GetPixelCacheNexusExtent() method is:
2657%
2658% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2659% NexusInfo *nexus_info)
2660%
2661% A description of each parameter follows:
2662%
2663% o nexus_info: the nexus info.
2664%
2665*/
2666MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2667 NexusInfo *nexus_info)
2668{
2669 CacheInfo
2670 *cache_info;
2671
2672 MagickSizeType
2673 extent;
2674
cristye7cc7cf2010-09-21 13:26:47 +00002675 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002676 cache_info=(CacheInfo *) cache;
2677 assert(cache_info->signature == MagickSignature);
2678 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2679 if (extent == 0)
2680 return((MagickSizeType) cache_info->columns*cache_info->rows);
2681 return(extent);
2682}
2683
2684/*
2685%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2686% %
2687% %
2688% %
2689+ 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 %
2690% %
2691% %
2692% %
2693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2694%
2695% GetPixelCacheNexusIndexes() returns the indexes associated with the
2696% specified cache nexus.
2697%
2698% The format of the GetPixelCacheNexusIndexes() method is:
2699%
2700% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2701% NexusInfo *nexus_info)
2702%
2703% A description of each parameter follows:
2704%
2705% o cache: the pixel cache.
2706%
2707% o nexus_info: the cache nexus to return the colormap indexes.
2708%
2709*/
2710MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2711 NexusInfo *nexus_info)
2712{
2713 CacheInfo
2714 *cache_info;
2715
cristye7cc7cf2010-09-21 13:26:47 +00002716 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002717 cache_info=(CacheInfo *) cache;
2718 assert(cache_info->signature == MagickSignature);
2719 if (cache_info->storage_class == UndefinedClass)
2720 return((IndexPacket *) NULL);
2721 return(nexus_info->indexes);
2722}
2723
2724/*
2725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2726% %
2727% %
2728% %
2729+ G e t P i x e l C a c h e N e x u s P i x e l s %
2730% %
2731% %
2732% %
2733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2734%
2735% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2736% cache nexus.
2737%
2738% The format of the GetPixelCacheNexusPixels() method is:
2739%
2740% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2741% NexusInfo *nexus_info)
2742%
2743% A description of each parameter follows:
2744%
2745% o cache: the pixel cache.
2746%
2747% o nexus_info: the cache nexus to return the pixels.
2748%
2749*/
2750MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2751 NexusInfo *nexus_info)
2752{
2753 CacheInfo
2754 *cache_info;
2755
cristye7cc7cf2010-09-21 13:26:47 +00002756 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002757 cache_info=(CacheInfo *) cache;
2758 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002759 if (cache_info->storage_class == UndefinedClass)
2760 return((PixelPacket *) NULL);
2761 return(nexus_info->pixels);
2762}
2763
2764/*
2765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2766% %
2767% %
2768% %
cristy056ba772010-01-02 23:33:54 +00002769+ G e t P i x e l C a c h e P i x e l s %
2770% %
2771% %
2772% %
2773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2774%
2775% GetPixelCachePixels() returns the pixels associated with the specified image.
2776%
2777% The format of the GetPixelCachePixels() method is:
2778%
cristyf84a1932010-01-03 18:00:18 +00002779% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2780% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002781%
2782% A description of each parameter follows:
2783%
2784% o image: the image.
2785%
2786% o length: the pixel cache length.
2787%
cristyf84a1932010-01-03 18:00:18 +00002788% o exception: return any errors or warnings in this structure.
2789%
cristy056ba772010-01-02 23:33:54 +00002790*/
cristyf84a1932010-01-03 18:00:18 +00002791MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2792 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002793{
2794 CacheInfo
2795 *cache_info;
2796
2797 assert(image != (const Image *) NULL);
2798 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002799 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002800 assert(length != (MagickSizeType *) NULL);
2801 assert(exception != (ExceptionInfo *) NULL);
2802 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002803 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002804 assert(cache_info->signature == MagickSignature);
2805 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002806 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002807 return((void *) NULL);
2808 *length=cache_info->length;
2809 return((void *) cache_info->pixels);
2810}
2811
2812/*
2813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2814% %
2815% %
2816% %
cristyb32b90a2009-09-07 21:45:48 +00002817+ 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 +00002818% %
2819% %
2820% %
2821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2822%
2823% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2824%
2825% The format of the GetPixelCacheStorageClass() method is:
2826%
2827% ClassType GetPixelCacheStorageClass(Cache cache)
2828%
2829% A description of each parameter follows:
2830%
2831% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2832%
2833% o cache: the pixel cache.
2834%
2835*/
2836MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2837{
2838 CacheInfo
2839 *cache_info;
2840
2841 assert(cache != (Cache) NULL);
2842 cache_info=(CacheInfo *) cache;
2843 assert(cache_info->signature == MagickSignature);
2844 if (cache_info->debug != MagickFalse)
2845 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2846 cache_info->filename);
2847 return(cache_info->storage_class);
2848}
2849
2850/*
2851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2852% %
2853% %
2854% %
cristyb32b90a2009-09-07 21:45:48 +00002855+ G e t P i x e l C a c h e T i l e S i z e %
2856% %
2857% %
2858% %
2859%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2860%
2861% GetPixelCacheTileSize() returns the pixel cache tile size.
2862%
2863% The format of the GetPixelCacheTileSize() method is:
2864%
cristybb503372010-05-27 20:51:26 +00002865% void GetPixelCacheTileSize(const Image *image,size_t *width,
2866% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002867%
2868% A description of each parameter follows:
2869%
2870% o image: the image.
2871%
2872% o width: the optimize cache tile width in pixels.
2873%
2874% o height: the optimize cache tile height in pixels.
2875%
2876*/
cristybb503372010-05-27 20:51:26 +00002877MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2878 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002879{
cristyb32b90a2009-09-07 21:45:48 +00002880 assert(image != (Image *) NULL);
2881 assert(image->signature == MagickSignature);
2882 if (image->debug != MagickFalse)
2883 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyb32b90a2009-09-07 21:45:48 +00002884 *width=2048UL/sizeof(PixelPacket);
2885 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002886 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002887 *height=(*width);
2888}
2889
2890/*
2891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2892% %
2893% %
2894% %
2895+ G e t P i x e l C a c h e T y p e %
2896% %
2897% %
2898% %
2899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2900%
2901% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2902%
2903% The format of the GetPixelCacheType() method is:
2904%
2905% CacheType GetPixelCacheType(const Image *image)
2906%
2907% A description of each parameter follows:
2908%
2909% o image: the image.
2910%
2911*/
2912MagickExport CacheType GetPixelCacheType(const Image *image)
2913{
2914 CacheInfo
2915 *cache_info;
2916
2917 assert(image != (Image *) NULL);
2918 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002919 assert(image->cache != (Cache) NULL);
2920 cache_info=(CacheInfo *) image->cache;
2921 assert(cache_info->signature == MagickSignature);
2922 return(cache_info->type);
2923}
2924
2925/*
2926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927% %
2928% %
2929% %
cristy3ed852e2009-09-05 21:47:34 +00002930+ 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 %
2931% %
2932% %
2933% %
2934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2935%
2936% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2937% pixel cache. A virtual pixel is any pixel access that is outside the
2938% boundaries of the image cache.
2939%
2940% The format of the GetPixelCacheVirtualMethod() method is:
2941%
2942% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2943%
2944% A description of each parameter follows:
2945%
2946% o image: the image.
2947%
2948*/
2949MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2950{
2951 CacheInfo
2952 *cache_info;
2953
2954 assert(image != (Image *) NULL);
2955 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002956 assert(image->cache != (Cache) NULL);
2957 cache_info=(CacheInfo *) image->cache;
2958 assert(cache_info->signature == MagickSignature);
2959 return(cache_info->virtual_pixel_method);
2960}
2961
2962/*
2963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2964% %
2965% %
2966% %
2967+ 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 %
2968% %
2969% %
2970% %
2971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2972%
2973% GetVirtualIndexesFromCache() returns the indexes associated with the last
2974% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2975%
2976% The format of the GetVirtualIndexesFromCache() method is:
2977%
2978% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2979%
2980% A description of each parameter follows:
2981%
2982% o image: the image.
2983%
2984*/
2985static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2986{
2987 CacheInfo
2988 *cache_info;
2989
cristy5c9e6f22010-09-17 17:31:01 +00002990 const int
2991 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002992
cristye7cc7cf2010-09-21 13:26:47 +00002993 assert(image != (const Image *) NULL);
2994 assert(image->signature == MagickSignature);
2995 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002996 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002997 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002998 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002999 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003000}
3001
3002/*
3003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3004% %
3005% %
3006% %
3007+ 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 %
3008% %
3009% %
3010% %
3011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3012%
3013% GetVirtualIndexesFromNexus() returns the indexes associated with the
3014% specified cache nexus.
3015%
3016% The format of the GetVirtualIndexesFromNexus() method is:
3017%
3018% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3019% NexusInfo *nexus_info)
3020%
3021% A description of each parameter follows:
3022%
3023% o cache: the pixel cache.
3024%
3025% o nexus_info: the cache nexus to return the colormap indexes.
3026%
3027*/
3028MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3029 NexusInfo *nexus_info)
3030{
3031 CacheInfo
3032 *cache_info;
3033
cristye7cc7cf2010-09-21 13:26:47 +00003034 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003035 cache_info=(CacheInfo *) cache;
3036 assert(cache_info->signature == MagickSignature);
3037 if (cache_info->storage_class == UndefinedClass)
3038 return((IndexPacket *) NULL);
3039 return(nexus_info->indexes);
3040}
3041
3042/*
3043%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3044% %
3045% %
3046% %
3047% G e t V i r t u a l I n d e x Q u e u e %
3048% %
3049% %
3050% %
3051%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3052%
3053% GetVirtualIndexQueue() returns the virtual black channel or the
3054% colormap indexes associated with the last call to QueueAuthenticPixels() or
3055% GetVirtualPixels(). NULL is returned if the black channel or colormap
3056% indexes are not available.
3057%
3058% The format of the GetVirtualIndexQueue() method is:
3059%
3060% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3061%
3062% A description of each parameter follows:
3063%
3064% o image: the image.
3065%
3066*/
3067MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3068{
3069 CacheInfo
3070 *cache_info;
3071
cristy2036f5c2010-09-19 21:18:17 +00003072 const int
3073 id = GetOpenMPThreadId();
3074
cristy3ed852e2009-09-05 21:47:34 +00003075 assert(image != (const Image *) NULL);
3076 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003077 assert(image->cache != (Cache) NULL);
3078 cache_info=(CacheInfo *) image->cache;
3079 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003080 if (cache_info->methods.get_virtual_indexes_from_handler !=
3081 (GetVirtualIndexesFromHandler) NULL)
3082 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003083 assert(id < (int) cache_info->number_threads);
3084 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003085}
3086
3087/*
3088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3089% %
3090% %
3091% %
3092+ 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 %
3093% %
3094% %
3095% %
3096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3097%
3098% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3099% pixel cache as defined by the geometry parameters. A pointer to the pixels
3100% is returned if the pixels are transferred, otherwise a NULL is returned.
3101%
3102% The format of the GetVirtualPixelsFromNexus() method is:
3103%
3104% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003105% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003106% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3107% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003108%
3109% A description of each parameter follows:
3110%
3111% o image: the image.
3112%
3113% o virtual_pixel_method: the virtual pixel method.
3114%
3115% o x,y,columns,rows: These values define the perimeter of a region of
3116% pixels.
3117%
3118% o nexus_info: the cache nexus to acquire.
3119%
3120% o exception: return any errors or warnings in this structure.
3121%
3122*/
3123
cristybb503372010-05-27 20:51:26 +00003124static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003125 DitherMatrix[64] =
3126 {
3127 0, 48, 12, 60, 3, 51, 15, 63,
3128 32, 16, 44, 28, 35, 19, 47, 31,
3129 8, 56, 4, 52, 11, 59, 7, 55,
3130 40, 24, 36, 20, 43, 27, 39, 23,
3131 2, 50, 14, 62, 1, 49, 13, 61,
3132 34, 18, 46, 30, 33, 17, 45, 29,
3133 10, 58, 6, 54, 9, 57, 5, 53,
3134 42, 26, 38, 22, 41, 25, 37, 21
3135 };
3136
cristybb503372010-05-27 20:51:26 +00003137static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003138{
cristybb503372010-05-27 20:51:26 +00003139 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003140 index;
3141
3142 index=x+DitherMatrix[x & 0x07]-32L;
3143 if (index < 0L)
3144 return(0L);
cristybb503372010-05-27 20:51:26 +00003145 if (index >= (ssize_t) columns)
3146 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003147 return(index);
3148}
3149
cristybb503372010-05-27 20:51:26 +00003150static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003151{
cristybb503372010-05-27 20:51:26 +00003152 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003153 index;
3154
3155 index=y+DitherMatrix[y & 0x07]-32L;
3156 if (index < 0L)
3157 return(0L);
cristybb503372010-05-27 20:51:26 +00003158 if (index >= (ssize_t) rows)
3159 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003160 return(index);
3161}
3162
cristybb503372010-05-27 20:51:26 +00003163static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003164{
3165 if (x < 0L)
3166 return(0L);
cristybb503372010-05-27 20:51:26 +00003167 if (x >= (ssize_t) columns)
3168 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003169 return(x);
3170}
3171
cristybb503372010-05-27 20:51:26 +00003172static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003173{
3174 if (y < 0L)
3175 return(0L);
cristybb503372010-05-27 20:51:26 +00003176 if (y >= (ssize_t) rows)
3177 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003178 return(y);
3179}
3180
cristybb503372010-05-27 20:51:26 +00003181static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003182{
cristybb503372010-05-27 20:51:26 +00003183 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003184}
3185
cristybb503372010-05-27 20:51:26 +00003186static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003187{
cristybb503372010-05-27 20:51:26 +00003188 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003189}
3190
3191/*
3192 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3193 returns not only the quotient (tile the offset falls in) but also the positive
3194 remainer within that tile such that 0 <= remainder < extent. This method is
3195 essentially a ldiv() using a floored modulo division rather than the normal
3196 default truncated modulo division.
3197*/
cristybb503372010-05-27 20:51:26 +00003198static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3199 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003200{
3201 MagickModulo
3202 modulo;
3203
cristybb503372010-05-27 20:51:26 +00003204 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003205 if (offset < 0L)
3206 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003207 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003208 return(modulo);
3209}
3210
3211MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003212 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3213 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003214 ExceptionInfo *exception)
3215{
3216 CacheInfo
3217 *cache_info;
3218
cristyc3ec0d42010-04-07 01:18:08 +00003219 IndexPacket
3220 virtual_index;
3221
cristy3ed852e2009-09-05 21:47:34 +00003222 MagickOffsetType
3223 offset;
3224
3225 MagickSizeType
3226 length,
3227 number_pixels;
3228
3229 NexusInfo
3230 **virtual_nexus;
3231
3232 PixelPacket
3233 *pixels,
3234 virtual_pixel;
3235
3236 RectangleInfo
3237 region;
3238
3239 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003240 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003241
3242 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003243 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003244
3245 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003246 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003247
cristye076a6e2010-08-15 19:59:43 +00003248 register PixelPacket
3249 *restrict q;
3250
cristybb503372010-05-27 20:51:26 +00003251 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003252 u,
3253 v;
3254
cristy3ed852e2009-09-05 21:47:34 +00003255 /*
3256 Acquire pixels.
3257 */
cristye7cc7cf2010-09-21 13:26:47 +00003258 assert(image != (const Image *) NULL);
3259 assert(image->signature == MagickSignature);
3260 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003261 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003262 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003263 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003264 return((const PixelPacket *) NULL);
3265 region.x=x;
3266 region.y=y;
3267 region.width=columns;
3268 region.height=rows;
3269 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3270 if (pixels == (PixelPacket *) NULL)
3271 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003272 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3273 nexus_info->region.x;
3274 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3275 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003276 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3277 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003278 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3279 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003280 {
3281 MagickBooleanType
3282 status;
3283
3284 /*
3285 Pixel request is inside cache extents.
3286 */
3287 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3288 return(pixels);
3289 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3290 if (status == MagickFalse)
3291 return((const PixelPacket *) NULL);
3292 if ((cache_info->storage_class == PseudoClass) ||
3293 (cache_info->colorspace == CMYKColorspace))
3294 {
3295 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3296 if (status == MagickFalse)
3297 return((const PixelPacket *) NULL);
3298 }
3299 return(pixels);
3300 }
3301 /*
3302 Pixel request is outside cache extents.
3303 */
3304 q=pixels;
3305 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3306 virtual_nexus=AcquirePixelCacheNexus(1);
3307 if (virtual_nexus == (NexusInfo **) NULL)
3308 {
3309 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3310 "UnableToGetCacheNexus","`%s'",image->filename);
3311 return((const PixelPacket *) NULL);
3312 }
3313 switch (virtual_pixel_method)
3314 {
3315 case BlackVirtualPixelMethod:
3316 {
cristy4789f0d2010-01-10 00:01:06 +00003317 SetRedPixelComponent(&virtual_pixel,0);
3318 SetGreenPixelComponent(&virtual_pixel,0);
3319 SetBluePixelComponent(&virtual_pixel,0);
3320 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003321 break;
3322 }
3323 case GrayVirtualPixelMethod:
3324 {
cristy4e82e512011-04-24 01:33:42 +00003325 SetRedPixelComponent(&virtual_pixel,QuantumRange/2);
3326 SetGreenPixelComponent(&virtual_pixel,QuantumRange/2);
3327 SetBluePixelComponent(&virtual_pixel,QuantumRange/2);
cristy4789f0d2010-01-10 00:01:06 +00003328 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003329 break;
3330 }
3331 case TransparentVirtualPixelMethod:
3332 {
cristy4789f0d2010-01-10 00:01:06 +00003333 SetRedPixelComponent(&virtual_pixel,0);
3334 SetGreenPixelComponent(&virtual_pixel,0);
3335 SetBluePixelComponent(&virtual_pixel,0);
3336 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003337 break;
3338 }
3339 case MaskVirtualPixelMethod:
3340 case WhiteVirtualPixelMethod:
3341 {
cristy4e82e512011-04-24 01:33:42 +00003342 SetRedPixelComponent(&virtual_pixel,QuantumRange);
3343 SetGreenPixelComponent(&virtual_pixel,QuantumRange);
3344 SetBluePixelComponent(&virtual_pixel,QuantumRange);
cristy4789f0d2010-01-10 00:01:06 +00003345 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003346 break;
3347 }
3348 default:
3349 {
3350 virtual_pixel=image->background_color;
3351 break;
3352 }
3353 }
cristyc3ec0d42010-04-07 01:18:08 +00003354 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003355 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003356 {
cristybb503372010-05-27 20:51:26 +00003357 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003358 {
3359 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003360 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003361 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3362 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003363 {
3364 MagickModulo
3365 x_modulo,
3366 y_modulo;
3367
3368 /*
3369 Transfer a single pixel.
3370 */
3371 length=(MagickSizeType) 1;
3372 switch (virtual_pixel_method)
3373 {
3374 case BackgroundVirtualPixelMethod:
3375 case ConstantVirtualPixelMethod:
3376 case BlackVirtualPixelMethod:
3377 case GrayVirtualPixelMethod:
3378 case TransparentVirtualPixelMethod:
3379 case MaskVirtualPixelMethod:
3380 case WhiteVirtualPixelMethod:
3381 {
3382 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003383 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003384 break;
3385 }
3386 case EdgeVirtualPixelMethod:
3387 default:
3388 {
3389 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003390 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003391 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003392 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003393 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003394 break;
3395 }
3396 case RandomVirtualPixelMethod:
3397 {
3398 if (cache_info->random_info == (RandomInfo *) NULL)
3399 cache_info->random_info=AcquireRandomInfo();
3400 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003401 RandomX(cache_info->random_info,cache_info->columns),
3402 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003403 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003404 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003405 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003406 break;
3407 }
3408 case DitherVirtualPixelMethod:
3409 {
3410 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003411 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003412 1UL,1UL,*virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003413 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003414 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003415 break;
3416 }
3417 case TileVirtualPixelMethod:
3418 {
3419 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3420 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003422 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003423 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003424 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003425 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003426 break;
3427 }
3428 case MirrorVirtualPixelMethod:
3429 {
3430 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3431 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003432 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003433 x_modulo.remainder-1L;
3434 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3435 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003436 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003437 y_modulo.remainder-1L;
3438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003439 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003440 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003441 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003442 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003443 break;
3444 }
3445 case CheckerTileVirtualPixelMethod:
3446 {
3447 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3448 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3449 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3450 {
3451 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003452 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003453 break;
3454 }
3455 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003456 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003457 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003458 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003459 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003460 break;
3461 }
3462 case HorizontalTileVirtualPixelMethod:
3463 {
cristybb503372010-05-27 20:51:26 +00003464 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003465 {
3466 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003467 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003468 break;
3469 }
3470 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3471 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3472 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003473 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003474 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003475 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003476 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003477 break;
3478 }
3479 case VerticalTileVirtualPixelMethod:
3480 {
cristybb503372010-05-27 20:51:26 +00003481 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003482 {
3483 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003484 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003485 break;
3486 }
3487 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3488 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3489 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003490 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003491 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003492 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003493 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003494 break;
3495 }
3496 case HorizontalTileEdgeVirtualPixelMethod:
3497 {
3498 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3499 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003500 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003501 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003502 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003503 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003504 break;
3505 }
3506 case VerticalTileEdgeVirtualPixelMethod:
3507 {
3508 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3509 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003510 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003511 *virtual_nexus,exception);
cristyc3ec0d42010-04-07 01:18:08 +00003512 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
cristy0a36c742010-10-03 02:10:53 +00003513 *virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003514 break;
3515 }
3516 }
3517 if (p == (const PixelPacket *) NULL)
3518 break;
3519 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003520 if ((indexes != (IndexPacket *) NULL) &&
3521 (virtual_indexes != (const IndexPacket *) NULL))
3522 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003523 continue;
3524 }
3525 /*
3526 Transfer a run of pixels.
3527 */
3528 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristy0a36c742010-10-03 02:10:53 +00003529 (size_t) length,1UL,*virtual_nexus,exception);
cristy3ed852e2009-09-05 21:47:34 +00003530 if (p == (const PixelPacket *) NULL)
3531 break;
cristy0a36c742010-10-03 02:10:53 +00003532 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
cristy8f036fe2010-09-18 02:02:00 +00003533 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003534 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003535 if ((indexes != (IndexPacket *) NULL) &&
3536 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003537 {
cristy8f036fe2010-09-18 02:02:00 +00003538 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003539 sizeof(*virtual_indexes));
3540 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003541 }
3542 }
3543 }
3544 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3545 return(pixels);
3546}
3547
3548/*
3549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3550% %
3551% %
3552% %
3553+ G e t V i r t u a l P i x e l C a c h e %
3554% %
3555% %
3556% %
3557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3558%
3559% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3560% cache as defined by the geometry parameters. A pointer to the pixels
3561% is returned if the pixels are transferred, otherwise a NULL is returned.
3562%
3563% The format of the GetVirtualPixelCache() method is:
3564%
3565% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003566% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3567% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003568% ExceptionInfo *exception)
3569%
3570% A description of each parameter follows:
3571%
3572% o image: the image.
3573%
3574% o virtual_pixel_method: the virtual pixel method.
3575%
3576% o x,y,columns,rows: These values define the perimeter of a region of
3577% pixels.
3578%
3579% o exception: return any errors or warnings in this structure.
3580%
3581*/
3582static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003583 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3584 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003585{
3586 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003587 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003588
cristy5c9e6f22010-09-17 17:31:01 +00003589 const int
3590 id = GetOpenMPThreadId();
3591
cristye7cc7cf2010-09-21 13:26:47 +00003592 assert(image != (const Image *) NULL);
3593 assert(image->signature == MagickSignature);
3594 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003595 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003596 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003597 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003598 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3599 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003600}
3601
3602/*
3603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604% %
3605% %
3606% %
3607% G e t V i r t u a l P i x e l Q u e u e %
3608% %
3609% %
3610% %
3611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3612%
3613% GetVirtualPixelQueue() returns the virtual pixels associated with the
3614% last call to QueueAuthenticPixels() or GetVirtualPixels().
3615%
3616% The format of the GetVirtualPixelQueue() method is:
3617%
3618% const PixelPacket *GetVirtualPixelQueue(const Image image)
3619%
3620% A description of each parameter follows:
3621%
3622% o image: the image.
3623%
3624*/
3625MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3626{
3627 CacheInfo
3628 *cache_info;
3629
cristy2036f5c2010-09-19 21:18:17 +00003630 const int
3631 id = GetOpenMPThreadId();
3632
cristy3ed852e2009-09-05 21:47:34 +00003633 assert(image != (const Image *) NULL);
3634 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003635 assert(image->cache != (Cache) NULL);
3636 cache_info=(CacheInfo *) image->cache;
3637 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003638 if (cache_info->methods.get_virtual_pixels_handler !=
3639 (GetVirtualPixelsHandler) NULL)
3640 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003641 assert(id < (int) cache_info->number_threads);
3642 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003643}
3644
3645/*
3646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647% %
3648% %
3649% %
3650% G e t V i r t u a l P i x e l s %
3651% %
3652% %
3653% %
3654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3655%
3656% GetVirtualPixels() returns an immutable pixel region. If the
3657% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003658% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003659% copy of the pixels or it may point to the original pixels in memory.
3660% Performance is maximized if the selected region is part of one row, or one
3661% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003662% (without a copy) if the image is in memory, or in a memory-mapped file. The
3663% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003664%
3665% Pixels accessed via the returned pointer represent a simple array of type
3666% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3667% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3668% the black color component or to obtain the colormap indexes (of type
3669% IndexPacket) corresponding to the region.
3670%
3671% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3672%
3673% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3674% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3675% GetCacheViewAuthenticPixels() instead.
3676%
3677% The format of the GetVirtualPixels() method is:
3678%
cristybb503372010-05-27 20:51:26 +00003679% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3680% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003681% ExceptionInfo *exception)
3682%
3683% A description of each parameter follows:
3684%
3685% o image: the image.
3686%
3687% o x,y,columns,rows: These values define the perimeter of a region of
3688% pixels.
3689%
3690% o exception: return any errors or warnings in this structure.
3691%
3692*/
3693MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003694 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3695 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003696{
3697 CacheInfo
3698 *cache_info;
3699
cristy2036f5c2010-09-19 21:18:17 +00003700 const int
3701 id = GetOpenMPThreadId();
3702
cristy3ed852e2009-09-05 21:47:34 +00003703 assert(image != (const Image *) NULL);
3704 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003705 assert(image->cache != (Cache) NULL);
3706 cache_info=(CacheInfo *) image->cache;
3707 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003708 if (cache_info->methods.get_virtual_pixel_handler !=
3709 (GetVirtualPixelHandler) NULL)
3710 return(cache_info->methods.get_virtual_pixel_handler(image,
3711 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003712 assert(id < (int) cache_info->number_threads);
3713 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3714 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003715}
3716
3717/*
3718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3719% %
3720% %
3721% %
3722+ 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 %
3723% %
3724% %
3725% %
3726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3727%
3728% GetVirtualPixelsCache() returns the pixels associated with the last call
3729% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3730%
3731% The format of the GetVirtualPixelsCache() method is:
3732%
3733% PixelPacket *GetVirtualPixelsCache(const Image *image)
3734%
3735% A description of each parameter follows:
3736%
3737% o image: the image.
3738%
3739*/
3740static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3741{
3742 CacheInfo
3743 *cache_info;
3744
cristy5c9e6f22010-09-17 17:31:01 +00003745 const int
3746 id = GetOpenMPThreadId();
3747
cristye7cc7cf2010-09-21 13:26:47 +00003748 assert(image != (const Image *) NULL);
3749 assert(image->signature == MagickSignature);
3750 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003751 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003752 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003753 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003754 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003755}
3756
3757/*
3758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3759% %
3760% %
3761% %
3762+ G e t V i r t u a l P i x e l s N e x u s %
3763% %
3764% %
3765% %
3766%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3767%
3768% GetVirtualPixelsNexus() returns the pixels associated with the specified
3769% cache nexus.
3770%
3771% The format of the GetVirtualPixelsNexus() method is:
3772%
3773% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3774% NexusInfo *nexus_info)
3775%
3776% A description of each parameter follows:
3777%
3778% o cache: the pixel cache.
3779%
3780% o nexus_info: the cache nexus to return the colormap pixels.
3781%
3782*/
3783MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3784 NexusInfo *nexus_info)
3785{
3786 CacheInfo
3787 *cache_info;
3788
cristye7cc7cf2010-09-21 13:26:47 +00003789 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003790 cache_info=(CacheInfo *) cache;
3791 assert(cache_info->signature == MagickSignature);
3792 if (cache_info->storage_class == UndefinedClass)
3793 return((PixelPacket *) NULL);
3794 return((const PixelPacket *) nexus_info->pixels);
3795}
3796
3797/*
3798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3799% %
3800% %
3801% %
3802+ M a s k P i x e l C a c h e N e x u s %
3803% %
3804% %
3805% %
3806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3807%
3808% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3809% The method returns MagickTrue if the pixel region is masked, otherwise
3810% MagickFalse.
3811%
3812% The format of the MaskPixelCacheNexus() method is:
3813%
3814% MagickBooleanType MaskPixelCacheNexus(Image *image,
3815% NexusInfo *nexus_info,ExceptionInfo *exception)
3816%
3817% A description of each parameter follows:
3818%
3819% o image: the image.
3820%
3821% o nexus_info: the cache nexus to clip.
3822%
3823% o exception: return any errors or warnings in this structure.
3824%
3825*/
3826
3827static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3828 const MagickRealType alpha,const MagickPixelPacket *q,
3829 const MagickRealType beta,MagickPixelPacket *composite)
3830{
3831 MagickRealType
3832 gamma;
3833
3834 if (alpha == TransparentOpacity)
3835 {
3836 *composite=(*q);
3837 return;
3838 }
3839 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3840 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003841 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3842 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3843 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003844 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3845 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3846}
3847
3848static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3849 ExceptionInfo *exception)
3850{
3851 CacheInfo
3852 *cache_info;
3853
3854 MagickPixelPacket
3855 alpha,
3856 beta;
3857
3858 MagickSizeType
3859 number_pixels;
3860
3861 NexusInfo
3862 **clip_nexus,
3863 **image_nexus;
3864
3865 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003866 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003867
3868 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003869 *restrict nexus_indexes,
3870 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003871
cristy3ed852e2009-09-05 21:47:34 +00003872 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003873 *restrict p,
3874 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003875
cristye076a6e2010-08-15 19:59:43 +00003876 register ssize_t
3877 i;
3878
cristy3ed852e2009-09-05 21:47:34 +00003879 /*
3880 Apply clip mask.
3881 */
3882 if (image->debug != MagickFalse)
3883 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3884 if (image->mask == (Image *) NULL)
3885 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003886 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003887 if (cache_info == (Cache) NULL)
3888 return(MagickFalse);
3889 image_nexus=AcquirePixelCacheNexus(1);
3890 clip_nexus=AcquirePixelCacheNexus(1);
3891 if ((image_nexus == (NexusInfo **) NULL) ||
3892 (clip_nexus == (NexusInfo **) NULL))
3893 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003894 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3895 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3896 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003897 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3898 q=nexus_info->pixels;
3899 nexus_indexes=nexus_info->indexes;
3900 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3901 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3902 nexus_info->region.height,clip_nexus[0],&image->exception);
3903 GetMagickPixelPacket(image,&alpha);
3904 GetMagickPixelPacket(image,&beta);
3905 number_pixels=(MagickSizeType) nexus_info->region.width*
3906 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003907 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003908 {
3909 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3910 break;
3911 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3912 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3913 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3914 &alpha,alpha.opacity,&beta);
cristyb40bd892011-04-23 00:52:38 +00003915 SetRedPixelComponent(q,ClampToQuantum(beta.red));
3916 SetGreenPixelComponent(q,ClampToQuantum(beta.green));
3917 SetBluePixelComponent(q,ClampToQuantum(beta.blue));
3918 SetOpacityPixelComponent(q,ClampToQuantum(beta.opacity));
cristy3ed852e2009-09-05 21:47:34 +00003919 if (cache_info->active_index_channel != MagickFalse)
cristyc8d25bc2011-04-29 02:19:30 +00003920 SetIndexPixelComponent(nexus_indexes+i,GetIndexPixelComponent(indexes+i));
cristy3ed852e2009-09-05 21:47:34 +00003921 p++;
3922 q++;
3923 r++;
3924 }
3925 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3926 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003927 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003928 return(MagickFalse);
3929 return(MagickTrue);
3930}
3931
3932/*
3933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3934% %
3935% %
3936% %
3937+ O p e n P i x e l C a c h e %
3938% %
3939% %
3940% %
3941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3942%
3943% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3944% dimensions, allocating space for the image pixels and optionally the
3945% colormap indexes, and memory mapping the cache if it is disk based. The
3946% cache nexus array is initialized as well.
3947%
3948% The format of the OpenPixelCache() method is:
3949%
3950% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3951% ExceptionInfo *exception)
3952%
3953% A description of each parameter follows:
3954%
3955% o image: the image.
3956%
3957% o mode: ReadMode, WriteMode, or IOMode.
3958%
3959% o exception: return any errors or warnings in this structure.
3960%
3961*/
3962
cristyd43a46b2010-01-21 02:13:41 +00003963static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003964{
3965 cache_info->mapped=MagickFalse;
3966 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3967 cache_info->length);
3968 if (cache_info->pixels == (PixelPacket *) NULL)
3969 {
3970 cache_info->mapped=MagickTrue;
3971 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3972 cache_info->length);
3973 }
3974}
3975
3976static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3977{
3978 CacheInfo
3979 *cache_info;
3980
3981 MagickOffsetType
3982 count,
3983 extent,
3984 offset;
3985
3986 cache_info=(CacheInfo *) image->cache;
3987 if (image->debug != MagickFalse)
3988 {
3989 char
3990 format[MaxTextExtent],
3991 message[MaxTextExtent];
3992
cristyb9080c92009-12-01 20:13:26 +00003993 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003994 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003995 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003996 cache_info->cache_filename,cache_info->file,format);
3997 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3998 }
3999 if (length != (MagickSizeType) ((MagickOffsetType) length))
4000 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00004001 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00004002 if (extent < 0)
4003 return(MagickFalse);
4004 if ((MagickSizeType) extent >= length)
4005 return(MagickTrue);
4006 offset=(MagickOffsetType) length-1;
4007 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4008 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4009}
4010
4011static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4012 ExceptionInfo *exception)
4013{
cristy3ed852e2009-09-05 21:47:34 +00004014 CacheInfo
4015 *cache_info,
4016 source_info;
4017
cristyf3a6a9d2010-11-07 21:02:56 +00004018 char
4019 format[MaxTextExtent],
4020 message[MaxTextExtent];
4021
cristy3ed852e2009-09-05 21:47:34 +00004022 MagickSizeType
4023 length,
4024 number_pixels;
4025
4026 MagickStatusType
4027 status;
4028
4029 size_t
cristye076a6e2010-08-15 19:59:43 +00004030 columns,
cristy3ed852e2009-09-05 21:47:34 +00004031 packet_size;
4032
cristye7cc7cf2010-09-21 13:26:47 +00004033 assert(image != (const Image *) NULL);
4034 assert(image->signature == MagickSignature);
4035 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004036 if (image->debug != MagickFalse)
4037 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4038 if ((image->columns == 0) || (image->rows == 0))
4039 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4040 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004041 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004042 source_info=(*cache_info);
4043 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004044 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4045 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004046 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004047 cache_info->rows=image->rows;
4048 cache_info->columns=image->columns;
cristyac319d22011-04-25 20:43:45 +00004049 cache_info->channels=image->channels;
cristy3ed852e2009-09-05 21:47:34 +00004050 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4051 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004052 if (image->ping != MagickFalse)
4053 {
4054 cache_info->storage_class=image->storage_class;
4055 cache_info->colorspace=image->colorspace;
4056 cache_info->type=PingCache;
4057 cache_info->pixels=(PixelPacket *) NULL;
4058 cache_info->indexes=(IndexPacket *) NULL;
4059 cache_info->length=0;
4060 return(MagickTrue);
4061 }
cristy3ed852e2009-09-05 21:47:34 +00004062 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4063 packet_size=sizeof(PixelPacket);
4064 if (cache_info->active_index_channel != MagickFalse)
4065 packet_size+=sizeof(IndexPacket);
4066 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004067 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004068 if (cache_info->columns != columns)
4069 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4070 image->filename);
4071 cache_info->length=length;
4072 status=AcquireMagickResource(AreaResource,cache_info->length);
4073 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4074 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4075 {
4076 status=AcquireMagickResource(MemoryResource,cache_info->length);
4077 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4078 (cache_info->type == MemoryCache))
4079 {
cristyd43a46b2010-01-21 02:13:41 +00004080 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004081 if (cache_info->pixels == (PixelPacket *) NULL)
4082 cache_info->pixels=source_info.pixels;
4083 else
4084 {
4085 /*
4086 Create memory pixel cache.
4087 */
4088 if (image->debug != MagickFalse)
4089 {
cristy97e7a572009-12-05 15:07:53 +00004090 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004091 format);
cristy3ed852e2009-09-05 21:47:34 +00004092 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004093 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004094 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004095 (double) cache_info->columns,(double) cache_info->rows,
4096 format);
cristy3ed852e2009-09-05 21:47:34 +00004097 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4098 message);
4099 }
4100 cache_info->storage_class=image->storage_class;
4101 cache_info->colorspace=image->colorspace;
4102 cache_info->type=MemoryCache;
4103 cache_info->indexes=(IndexPacket *) NULL;
4104 if (cache_info->active_index_channel != MagickFalse)
4105 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4106 number_pixels);
4107 if (source_info.storage_class != UndefinedClass)
4108 {
4109 status|=ClonePixelCachePixels(cache_info,&source_info,
4110 exception);
4111 RelinquishPixelCachePixels(&source_info);
4112 }
4113 return(MagickTrue);
4114 }
4115 }
4116 RelinquishMagickResource(MemoryResource,cache_info->length);
4117 }
4118 /*
4119 Create pixel cache on disk.
4120 */
4121 status=AcquireMagickResource(DiskResource,cache_info->length);
4122 if (status == MagickFalse)
4123 {
4124 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4125 "CacheResourcesExhausted","`%s'",image->filename);
4126 return(MagickFalse);
4127 }
4128 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4129 {
4130 RelinquishMagickResource(DiskResource,cache_info->length);
4131 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4132 image->filename);
4133 return(MagickFalse);
4134 }
4135 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4136 cache_info->length);
4137 if (status == MagickFalse)
4138 {
4139 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4140 image->filename);
4141 return(MagickFalse);
4142 }
4143 cache_info->storage_class=image->storage_class;
4144 cache_info->colorspace=image->colorspace;
4145 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4146 status=AcquireMagickResource(AreaResource,cache_info->length);
4147 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4148 cache_info->type=DiskCache;
4149 else
4150 {
4151 status=AcquireMagickResource(MapResource,cache_info->length);
4152 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4153 (cache_info->type != MemoryCache))
4154 cache_info->type=DiskCache;
4155 else
4156 {
4157 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4158 cache_info->offset,(size_t) cache_info->length);
4159 if (cache_info->pixels == (PixelPacket *) NULL)
4160 {
4161 cache_info->pixels=source_info.pixels;
4162 cache_info->type=DiskCache;
4163 }
4164 else
4165 {
4166 /*
4167 Create file-backed memory-mapped pixel cache.
4168 */
4169 (void) ClosePixelCacheOnDisk(cache_info);
4170 cache_info->type=MapCache;
4171 cache_info->mapped=MagickTrue;
4172 cache_info->indexes=(IndexPacket *) NULL;
4173 if (cache_info->active_index_channel != MagickFalse)
4174 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4175 number_pixels);
4176 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4177 {
4178 status=ClonePixelCachePixels(cache_info,&source_info,
4179 exception);
4180 RelinquishPixelCachePixels(&source_info);
4181 }
4182 if (image->debug != MagickFalse)
4183 {
cristy97e7a572009-12-05 15:07:53 +00004184 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004185 format);
cristy3ed852e2009-09-05 21:47:34 +00004186 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004187 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004188 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004189 cache_info->file,(double) cache_info->columns,(double)
4190 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004191 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4192 message);
4193 }
4194 return(MagickTrue);
4195 }
4196 }
4197 RelinquishMagickResource(MapResource,cache_info->length);
4198 }
4199 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4200 {
4201 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4202 RelinquishPixelCachePixels(&source_info);
4203 }
4204 if (image->debug != MagickFalse)
4205 {
cristyb9080c92009-12-01 20:13:26 +00004206 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004207 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004208 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4209 cache_info->cache_filename,cache_info->file,(double)
4210 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004211 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4212 }
4213 return(MagickTrue);
4214}
4215
4216/*
4217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4218% %
4219% %
4220% %
4221+ P e r s i s t P i x e l C a c h e %
4222% %
4223% %
4224% %
4225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4226%
4227% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4228% persistent pixel cache is one that resides on disk and is not destroyed
4229% when the program exits.
4230%
4231% The format of the PersistPixelCache() method is:
4232%
4233% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4234% const MagickBooleanType attach,MagickOffsetType *offset,
4235% ExceptionInfo *exception)
4236%
4237% A description of each parameter follows:
4238%
4239% o image: the image.
4240%
4241% o filename: the persistent pixel cache filename.
4242%
cristyf3a6a9d2010-11-07 21:02:56 +00004243% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004244%
cristy3ed852e2009-09-05 21:47:34 +00004245% o initialize: A value other than zero initializes the persistent pixel
4246% cache.
4247%
4248% o offset: the offset in the persistent cache to store pixels.
4249%
4250% o exception: return any errors or warnings in this structure.
4251%
4252*/
4253MagickExport MagickBooleanType PersistPixelCache(Image *image,
4254 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4255 ExceptionInfo *exception)
4256{
4257 CacheInfo
4258 *cache_info,
4259 *clone_info;
4260
4261 Image
4262 clone_image;
4263
cristy3ed852e2009-09-05 21:47:34 +00004264 MagickBooleanType
4265 status;
4266
cristye076a6e2010-08-15 19:59:43 +00004267 ssize_t
4268 page_size;
4269
cristy3ed852e2009-09-05 21:47:34 +00004270 assert(image != (Image *) NULL);
4271 assert(image->signature == MagickSignature);
4272 if (image->debug != MagickFalse)
4273 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4274 assert(image->cache != (void *) NULL);
4275 assert(filename != (const char *) NULL);
4276 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004277 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004278 cache_info=(CacheInfo *) image->cache;
4279 assert(cache_info->signature == MagickSignature);
4280 if (attach != MagickFalse)
4281 {
4282 /*
cristy01b7eb02009-09-10 23:10:14 +00004283 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004284 */
4285 if (image->debug != MagickFalse)
4286 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004287 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004288 (void) CopyMagickString(cache_info->cache_filename,filename,
4289 MaxTextExtent);
4290 cache_info->type=DiskCache;
4291 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004292 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004293 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004294 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004295 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004296 }
cristy01b7eb02009-09-10 23:10:14 +00004297 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4298 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004299 {
cristyf84a1932010-01-03 18:00:18 +00004300 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004301 if ((cache_info->mode != ReadMode) &&
4302 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004303 (cache_info->reference_count == 1))
4304 {
4305 int
4306 status;
4307
4308 /*
cristy01b7eb02009-09-10 23:10:14 +00004309 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004310 */
4311 status=rename(cache_info->cache_filename,filename);
4312 if (status == 0)
4313 {
4314 (void) CopyMagickString(cache_info->cache_filename,filename,
4315 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004316 *offset+=cache_info->length+page_size-(cache_info->length %
4317 page_size);
cristyf84a1932010-01-03 18:00:18 +00004318 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004319 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004320 if (image->debug != MagickFalse)
4321 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4322 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004323 return(MagickTrue);
4324 }
4325 }
cristyf84a1932010-01-03 18:00:18 +00004326 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004327 }
4328 /*
cristy01b7eb02009-09-10 23:10:14 +00004329 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004330 */
4331 clone_image=(*image);
4332 clone_info=(CacheInfo *) clone_image.cache;
4333 image->cache=ClonePixelCache(cache_info);
4334 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4335 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4336 cache_info->type=DiskCache;
4337 cache_info->offset=(*offset);
4338 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004339 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004340 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004341 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004342 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004343 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4344 return(status);
4345}
4346
4347/*
4348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4349% %
4350% %
4351% %
4352+ Q u e u e A u t h e n t i c N e x u s %
4353% %
4354% %
4355% %
4356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4357%
4358% QueueAuthenticNexus() allocates an region to store image pixels as defined
4359% by the region rectangle and returns a pointer to the region. This region is
4360% subsequently transferred from the pixel cache with
4361% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4362% pixels are transferred, otherwise a NULL is returned.
4363%
4364% The format of the QueueAuthenticNexus() method is:
4365%
cristy5f959472010-05-27 22:19:46 +00004366% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4367% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004368% NexusInfo *nexus_info,ExceptionInfo *exception)
4369%
4370% A description of each parameter follows:
4371%
4372% o image: the image.
4373%
4374% o x,y,columns,rows: These values define the perimeter of a region of
4375% pixels.
4376%
4377% o nexus_info: the cache nexus to set.
4378%
4379% o exception: return any errors or warnings in this structure.
4380%
4381*/
cristybb503372010-05-27 20:51:26 +00004382MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004383 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4384 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004385{
4386 CacheInfo
4387 *cache_info;
4388
4389 MagickOffsetType
4390 offset;
4391
4392 MagickSizeType
4393 number_pixels;
4394
4395 RectangleInfo
4396 region;
4397
4398 /*
4399 Validate pixel cache geometry.
4400 */
cristye7cc7cf2010-09-21 13:26:47 +00004401 assert(image != (const Image *) NULL);
4402 assert(image->signature == MagickSignature);
4403 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004404 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004405 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004406 if (cache_info == (Cache) NULL)
4407 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004408 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4409 {
4410 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4411 "NoPixelsDefinedInCache","`%s'",image->filename);
4412 return((PixelPacket *) NULL);
4413 }
cristybb503372010-05-27 20:51:26 +00004414 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4415 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004416 {
4417 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4418 "PixelsAreNotAuthentic","`%s'",image->filename);
4419 return((PixelPacket *) NULL);
4420 }
4421 offset=(MagickOffsetType) y*cache_info->columns+x;
4422 if (offset < 0)
4423 return((PixelPacket *) NULL);
4424 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4425 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4426 if ((MagickSizeType) offset >= number_pixels)
4427 return((PixelPacket *) NULL);
4428 /*
4429 Return pixel cache.
4430 */
4431 region.x=x;
4432 region.y=y;
4433 region.width=columns;
4434 region.height=rows;
4435 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4436}
4437
4438/*
4439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4440% %
4441% %
4442% %
4443+ 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 %
4444% %
4445% %
4446% %
4447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4448%
4449% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4450% defined by the region rectangle and returns a pointer to the region. This
4451% region is subsequently transferred from the pixel cache with
4452% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4453% pixels are transferred, otherwise a NULL is returned.
4454%
4455% The format of the QueueAuthenticPixelsCache() method is:
4456%
cristybb503372010-05-27 20:51:26 +00004457% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4458% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004459% ExceptionInfo *exception)
4460%
4461% A description of each parameter follows:
4462%
4463% o image: the image.
4464%
4465% o x,y,columns,rows: These values define the perimeter of a region of
4466% pixels.
4467%
4468% o exception: return any errors or warnings in this structure.
4469%
4470*/
cristybb503372010-05-27 20:51:26 +00004471static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4472 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004473 ExceptionInfo *exception)
4474{
4475 CacheInfo
4476 *cache_info;
4477
cristy5c9e6f22010-09-17 17:31:01 +00004478 const int
4479 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004480
cristye7cc7cf2010-09-21 13:26:47 +00004481 assert(image != (const Image *) NULL);
4482 assert(image->signature == MagickSignature);
4483 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004484 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004485 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004486 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004487 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4488 exception));
cristy3ed852e2009-09-05 21:47:34 +00004489}
4490
4491/*
4492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4493% %
4494% %
4495% %
4496% Q u e u e A u t h e n t i c P i x e l s %
4497% %
4498% %
4499% %
4500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4501%
4502% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4503% successfully intialized a pointer to a PixelPacket array representing the
4504% region is returned, otherwise NULL is returned. The returned pointer may
4505% point to a temporary working buffer for the pixels or it may point to the
4506% final location of the pixels in memory.
4507%
4508% Write-only access means that any existing pixel values corresponding to
4509% the region are ignored. This is useful if the initial image is being
4510% created from scratch, or if the existing pixel values are to be
4511% completely replaced without need to refer to their pre-existing values.
4512% The application is free to read and write the pixel buffer returned by
4513% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4514% initialize the pixel array values. Initializing pixel array values is the
4515% application's responsibility.
4516%
4517% Performance is maximized if the selected region is part of one row, or
4518% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004519% pixels in-place (without a copy) if the image is in memory, or in a
4520% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004521% by the user.
4522%
4523% Pixels accessed via the returned pointer represent a simple array of type
4524% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4525% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4526% the black color component or the colormap indexes (of type IndexPacket)
4527% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4528% array has been updated, the changes must be saved back to the underlying
4529% image using SyncAuthenticPixels() or they may be lost.
4530%
4531% The format of the QueueAuthenticPixels() method is:
4532%
cristy5f959472010-05-27 22:19:46 +00004533% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4534% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004535% ExceptionInfo *exception)
4536%
4537% A description of each parameter follows:
4538%
4539% o image: the image.
4540%
4541% o x,y,columns,rows: These values define the perimeter of a region of
4542% pixels.
4543%
4544% o exception: return any errors or warnings in this structure.
4545%
4546*/
cristybb503372010-05-27 20:51:26 +00004547MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4548 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004549 ExceptionInfo *exception)
4550{
4551 CacheInfo
4552 *cache_info;
4553
cristy2036f5c2010-09-19 21:18:17 +00004554 const int
4555 id = GetOpenMPThreadId();
4556
cristy3ed852e2009-09-05 21:47:34 +00004557 assert(image != (Image *) NULL);
4558 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004559 assert(image->cache != (Cache) NULL);
4560 cache_info=(CacheInfo *) image->cache;
4561 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004562 if (cache_info->methods.queue_authentic_pixels_handler !=
4563 (QueueAuthenticPixelsHandler) NULL)
4564 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4565 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004566 assert(id < (int) cache_info->number_threads);
4567 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4568 exception));
cristy3ed852e2009-09-05 21:47:34 +00004569}
4570
4571/*
4572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4573% %
4574% %
4575% %
4576+ R e a d P i x e l C a c h e I n d e x e s %
4577% %
4578% %
4579% %
4580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4581%
4582% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4583% the pixel cache.
4584%
4585% The format of the ReadPixelCacheIndexes() method is:
4586%
4587% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4588% NexusInfo *nexus_info,ExceptionInfo *exception)
4589%
4590% A description of each parameter follows:
4591%
4592% o cache_info: the pixel cache.
4593%
4594% o nexus_info: the cache nexus to read the colormap indexes.
4595%
4596% o exception: return any errors or warnings in this structure.
4597%
4598*/
4599static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4600 NexusInfo *nexus_info,ExceptionInfo *exception)
4601{
4602 MagickOffsetType
4603 count,
4604 offset;
4605
4606 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004607 extent,
4608 length;
cristy3ed852e2009-09-05 21:47:34 +00004609
4610 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004611 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004612
cristybb503372010-05-27 20:51:26 +00004613 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004614 y;
4615
cristybb503372010-05-27 20:51:26 +00004616 size_t
cristy3ed852e2009-09-05 21:47:34 +00004617 rows;
4618
cristy3ed852e2009-09-05 21:47:34 +00004619 if (cache_info->active_index_channel == MagickFalse)
4620 return(MagickFalse);
4621 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4622 return(MagickTrue);
4623 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4624 nexus_info->region.x;
4625 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4626 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004627 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004628 q=nexus_info->indexes;
4629 switch (cache_info->type)
4630 {
4631 case MemoryCache:
4632 case MapCache:
4633 {
4634 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004635 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004636
4637 /*
4638 Read indexes from memory.
4639 */
cristydd341db2010-03-04 19:06:38 +00004640 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004641 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004642 {
cristy48078b12010-09-23 17:11:01 +00004643 length=extent;
cristydd341db2010-03-04 19:06:38 +00004644 rows=1UL;
4645 }
cristy3ed852e2009-09-05 21:47:34 +00004646 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004647 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004648 {
cristy8f036fe2010-09-18 02:02:00 +00004649 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004650 p+=cache_info->columns;
4651 q+=nexus_info->region.width;
4652 }
4653 break;
4654 }
4655 case DiskCache:
4656 {
4657 /*
4658 Read indexes from disk.
4659 */
4660 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4661 {
4662 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4663 cache_info->cache_filename);
4664 return(MagickFalse);
4665 }
cristydd341db2010-03-04 19:06:38 +00004666 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004667 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004668 {
cristy48078b12010-09-23 17:11:01 +00004669 length=extent;
cristydd341db2010-03-04 19:06:38 +00004670 rows=1UL;
4671 }
cristy48078b12010-09-23 17:11:01 +00004672 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004673 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004674 {
cristy48078b12010-09-23 17:11:01 +00004675 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristy3ed852e2009-09-05 21:47:34 +00004676 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4677 if ((MagickSizeType) count < length)
4678 break;
4679 offset+=cache_info->columns;
4680 q+=nexus_info->region.width;
4681 }
cristybb503372010-05-27 20:51:26 +00004682 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004683 {
4684 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4685 cache_info->cache_filename);
4686 return(MagickFalse);
4687 }
4688 break;
4689 }
4690 default:
4691 break;
4692 }
4693 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004694 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004695 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004696 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004697 nexus_info->region.width,(double) nexus_info->region.height,(double)
4698 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004699 return(MagickTrue);
4700}
4701
4702/*
4703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4704% %
4705% %
4706% %
4707+ R e a d P i x e l C a c h e P i x e l s %
4708% %
4709% %
4710% %
4711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4712%
4713% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4714% cache.
4715%
4716% The format of the ReadPixelCachePixels() method is:
4717%
4718% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4719% NexusInfo *nexus_info,ExceptionInfo *exception)
4720%
4721% A description of each parameter follows:
4722%
4723% o cache_info: the pixel cache.
4724%
4725% o nexus_info: the cache nexus to read the pixels.
4726%
4727% o exception: return any errors or warnings in this structure.
4728%
4729*/
4730static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4731 NexusInfo *nexus_info,ExceptionInfo *exception)
4732{
4733 MagickOffsetType
4734 count,
4735 offset;
4736
4737 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004738 extent,
4739 length;
cristy3ed852e2009-09-05 21:47:34 +00004740
cristy3ed852e2009-09-05 21:47:34 +00004741 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004742 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004743
cristye076a6e2010-08-15 19:59:43 +00004744 register ssize_t
4745 y;
4746
cristybb503372010-05-27 20:51:26 +00004747 size_t
cristy3ed852e2009-09-05 21:47:34 +00004748 rows;
4749
cristy3ed852e2009-09-05 21:47:34 +00004750 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4751 return(MagickTrue);
4752 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4753 nexus_info->region.x;
4754 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4755 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004756 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004757 q=nexus_info->pixels;
4758 switch (cache_info->type)
4759 {
4760 case MemoryCache:
4761 case MapCache:
4762 {
4763 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004764 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004765
4766 /*
4767 Read pixels from memory.
4768 */
cristydd341db2010-03-04 19:06:38 +00004769 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004770 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004771 {
cristy48078b12010-09-23 17:11:01 +00004772 length=extent;
cristydd341db2010-03-04 19:06:38 +00004773 rows=1UL;
4774 }
cristy3ed852e2009-09-05 21:47:34 +00004775 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004776 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004777 {
cristy8f036fe2010-09-18 02:02:00 +00004778 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004779 p+=cache_info->columns;
4780 q+=nexus_info->region.width;
4781 }
4782 break;
4783 }
4784 case DiskCache:
4785 {
4786 /*
4787 Read pixels from disk.
4788 */
4789 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4790 {
4791 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4792 cache_info->cache_filename);
4793 return(MagickFalse);
4794 }
cristydd341db2010-03-04 19:06:38 +00004795 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004796 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004797 {
cristy48078b12010-09-23 17:11:01 +00004798 length=extent;
cristydd341db2010-03-04 19:06:38 +00004799 rows=1UL;
4800 }
cristybb503372010-05-27 20:51:26 +00004801 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004802 {
4803 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4804 sizeof(*q),length,(unsigned char *) q);
4805 if ((MagickSizeType) count < length)
4806 break;
4807 offset+=cache_info->columns;
4808 q+=nexus_info->region.width;
4809 }
cristybb503372010-05-27 20:51:26 +00004810 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004811 {
4812 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4813 cache_info->cache_filename);
4814 return(MagickFalse);
4815 }
4816 break;
4817 }
4818 default:
4819 break;
4820 }
4821 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004822 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004823 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004824 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004825 nexus_info->region.width,(double) nexus_info->region.height,(double)
4826 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004827 return(MagickTrue);
4828}
4829
4830/*
4831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4832% %
4833% %
4834% %
4835+ R e f e r e n c e P i x e l C a c h e %
4836% %
4837% %
4838% %
4839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4840%
4841% ReferencePixelCache() increments the reference count associated with the
4842% pixel cache returning a pointer to the cache.
4843%
4844% The format of the ReferencePixelCache method is:
4845%
4846% Cache ReferencePixelCache(Cache cache_info)
4847%
4848% A description of each parameter follows:
4849%
4850% o cache_info: the pixel cache.
4851%
4852*/
4853MagickExport Cache ReferencePixelCache(Cache cache)
4854{
4855 CacheInfo
4856 *cache_info;
4857
4858 assert(cache != (Cache *) NULL);
4859 cache_info=(CacheInfo *) cache;
4860 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004861 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004862 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004863 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004864 return(cache_info);
4865}
4866
4867/*
4868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4869% %
4870% %
4871% %
4872+ S e t P i x e l C a c h e M e t h o d s %
4873% %
4874% %
4875% %
4876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4877%
4878% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4879%
4880% The format of the SetPixelCacheMethods() method is:
4881%
4882% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4883%
4884% A description of each parameter follows:
4885%
4886% o cache: the pixel cache.
4887%
4888% o cache_methods: Specifies a pointer to a CacheMethods structure.
4889%
4890*/
4891MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4892{
4893 CacheInfo
4894 *cache_info;
4895
4896 GetOneAuthenticPixelFromHandler
4897 get_one_authentic_pixel_from_handler;
4898
4899 GetOneVirtualPixelFromHandler
4900 get_one_virtual_pixel_from_handler;
4901
4902 /*
4903 Set cache pixel methods.
4904 */
4905 assert(cache != (Cache) NULL);
4906 assert(cache_methods != (CacheMethods *) NULL);
4907 cache_info=(CacheInfo *) cache;
4908 assert(cache_info->signature == MagickSignature);
4909 if (cache_info->debug != MagickFalse)
4910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4911 cache_info->filename);
4912 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4913 cache_info->methods.get_virtual_pixel_handler=
4914 cache_methods->get_virtual_pixel_handler;
4915 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4916 cache_info->methods.destroy_pixel_handler=
4917 cache_methods->destroy_pixel_handler;
4918 if (cache_methods->get_virtual_indexes_from_handler !=
4919 (GetVirtualIndexesFromHandler) NULL)
4920 cache_info->methods.get_virtual_indexes_from_handler=
4921 cache_methods->get_virtual_indexes_from_handler;
4922 if (cache_methods->get_authentic_pixels_handler !=
4923 (GetAuthenticPixelsHandler) NULL)
4924 cache_info->methods.get_authentic_pixels_handler=
4925 cache_methods->get_authentic_pixels_handler;
4926 if (cache_methods->queue_authentic_pixels_handler !=
4927 (QueueAuthenticPixelsHandler) NULL)
4928 cache_info->methods.queue_authentic_pixels_handler=
4929 cache_methods->queue_authentic_pixels_handler;
4930 if (cache_methods->sync_authentic_pixels_handler !=
4931 (SyncAuthenticPixelsHandler) NULL)
4932 cache_info->methods.sync_authentic_pixels_handler=
4933 cache_methods->sync_authentic_pixels_handler;
4934 if (cache_methods->get_authentic_pixels_from_handler !=
4935 (GetAuthenticPixelsFromHandler) NULL)
4936 cache_info->methods.get_authentic_pixels_from_handler=
4937 cache_methods->get_authentic_pixels_from_handler;
4938 if (cache_methods->get_authentic_indexes_from_handler !=
4939 (GetAuthenticIndexesFromHandler) NULL)
4940 cache_info->methods.get_authentic_indexes_from_handler=
4941 cache_methods->get_authentic_indexes_from_handler;
4942 get_one_virtual_pixel_from_handler=
4943 cache_info->methods.get_one_virtual_pixel_from_handler;
4944 if (get_one_virtual_pixel_from_handler !=
4945 (GetOneVirtualPixelFromHandler) NULL)
4946 cache_info->methods.get_one_virtual_pixel_from_handler=
4947 cache_methods->get_one_virtual_pixel_from_handler;
4948 get_one_authentic_pixel_from_handler=
4949 cache_methods->get_one_authentic_pixel_from_handler;
4950 if (get_one_authentic_pixel_from_handler !=
4951 (GetOneAuthenticPixelFromHandler) NULL)
4952 cache_info->methods.get_one_authentic_pixel_from_handler=
4953 cache_methods->get_one_authentic_pixel_from_handler;
4954}
4955
4956/*
4957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4958% %
4959% %
4960% %
4961+ S e t P i x e l C a c h e N e x u s P i x e l s %
4962% %
4963% %
4964% %
4965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4966%
4967% SetPixelCacheNexusPixels() defines the region of the cache for the
4968% specified cache nexus.
4969%
4970% The format of the SetPixelCacheNexusPixels() method is:
4971%
4972% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4973% const RectangleInfo *region,NexusInfo *nexus_info,
4974% ExceptionInfo *exception)
4975%
4976% A description of each parameter follows:
4977%
4978% o image: the image.
4979%
4980% o region: A pointer to the RectangleInfo structure that defines the
4981% region of this particular cache nexus.
4982%
4983% o nexus_info: the cache nexus to set.
4984%
4985% o exception: return any errors or warnings in this structure.
4986%
4987*/
cristyabd6e372010-09-15 19:11:26 +00004988
4989static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4990 NexusInfo *nexus_info,ExceptionInfo *exception)
4991{
4992 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4993 return(MagickFalse);
4994 nexus_info->mapped=MagickFalse;
4995 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4996 nexus_info->length);
4997 if (nexus_info->cache == (PixelPacket *) NULL)
4998 {
4999 nexus_info->mapped=MagickTrue;
5000 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
5001 nexus_info->length);
5002 }
5003 if (nexus_info->cache == (PixelPacket *) NULL)
5004 {
5005 (void) ThrowMagickException(exception,GetMagickModule(),
5006 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5007 cache_info->filename);
5008 return(MagickFalse);
5009 }
5010 return(MagickTrue);
5011}
5012
cristy3ed852e2009-09-05 21:47:34 +00005013static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5014 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5015{
5016 CacheInfo
5017 *cache_info;
5018
5019 MagickBooleanType
5020 status;
5021
cristy3ed852e2009-09-05 21:47:34 +00005022 MagickSizeType
5023 length,
5024 number_pixels;
5025
cristy3ed852e2009-09-05 21:47:34 +00005026 cache_info=(CacheInfo *) image->cache;
5027 assert(cache_info->signature == MagickSignature);
5028 if (cache_info->type == UndefinedCache)
5029 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005030 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005031 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5032 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005033 {
cristybb503372010-05-27 20:51:26 +00005034 ssize_t
cristybad067a2010-02-15 17:20:55 +00005035 x,
5036 y;
cristy3ed852e2009-09-05 21:47:34 +00005037
cristyeaedf062010-05-29 22:36:02 +00005038 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5039 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005040 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5041 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005042 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005043 ((nexus_info->region.width == cache_info->columns) ||
5044 ((nexus_info->region.width % cache_info->columns) == 0)))))
5045 {
5046 MagickOffsetType
5047 offset;
5048
5049 /*
5050 Pixels are accessed directly from memory.
5051 */
5052 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5053 nexus_info->region.x;
5054 nexus_info->pixels=cache_info->pixels+offset;
5055 nexus_info->indexes=(IndexPacket *) NULL;
5056 if (cache_info->active_index_channel != MagickFalse)
5057 nexus_info->indexes=cache_info->indexes+offset;
5058 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005059 }
5060 }
5061 /*
5062 Pixels are stored in a cache region until they are synced to the cache.
5063 */
5064 number_pixels=(MagickSizeType) nexus_info->region.width*
5065 nexus_info->region.height;
5066 length=number_pixels*sizeof(PixelPacket);
5067 if (cache_info->active_index_channel != MagickFalse)
5068 length+=number_pixels*sizeof(IndexPacket);
5069 if (nexus_info->cache == (PixelPacket *) NULL)
5070 {
5071 nexus_info->length=length;
5072 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5073 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005074 {
5075 nexus_info->length=0;
5076 return((PixelPacket *) NULL);
5077 }
cristy3ed852e2009-09-05 21:47:34 +00005078 }
5079 else
5080 if (nexus_info->length != length)
5081 {
5082 RelinquishCacheNexusPixels(nexus_info);
5083 nexus_info->length=length;
5084 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5085 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005086 {
5087 nexus_info->length=0;
5088 return((PixelPacket *) NULL);
5089 }
cristy3ed852e2009-09-05 21:47:34 +00005090 }
5091 nexus_info->pixels=nexus_info->cache;
5092 nexus_info->indexes=(IndexPacket *) NULL;
5093 if (cache_info->active_index_channel != MagickFalse)
5094 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5095 return(nexus_info->pixels);
5096}
5097
5098/*
5099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5100% %
5101% %
5102% %
5103% 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 %
5104% %
5105% %
5106% %
5107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5108%
5109% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5110% pixel cache and returns the previous setting. A virtual pixel is any pixel
5111% access that is outside the boundaries of the image cache.
5112%
5113% The format of the SetPixelCacheVirtualMethod() method is:
5114%
5115% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5116% const VirtualPixelMethod virtual_pixel_method)
5117%
5118% A description of each parameter follows:
5119%
5120% o image: the image.
5121%
5122% o virtual_pixel_method: choose the type of virtual pixel.
5123%
5124*/
5125MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5126 const VirtualPixelMethod virtual_pixel_method)
5127{
5128 CacheInfo
5129 *cache_info;
5130
5131 VirtualPixelMethod
5132 method;
5133
5134 assert(image != (Image *) NULL);
5135 assert(image->signature == MagickSignature);
5136 if (image->debug != MagickFalse)
5137 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5138 assert(image->cache != (Cache) NULL);
5139 cache_info=(CacheInfo *) image->cache;
5140 assert(cache_info->signature == MagickSignature);
5141 method=cache_info->virtual_pixel_method;
5142 cache_info->virtual_pixel_method=virtual_pixel_method;
5143 return(method);
5144}
5145
5146/*
5147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5148% %
5149% %
5150% %
5151+ 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 %
5152% %
5153% %
5154% %
5155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5156%
5157% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5158% in-memory or disk cache. The method returns MagickTrue if the pixel region
5159% is synced, otherwise MagickFalse.
5160%
5161% The format of the SyncAuthenticPixelCacheNexus() method is:
5162%
5163% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5164% NexusInfo *nexus_info,ExceptionInfo *exception)
5165%
5166% A description of each parameter follows:
5167%
5168% o image: the image.
5169%
5170% o nexus_info: the cache nexus to sync.
5171%
5172% o exception: return any errors or warnings in this structure.
5173%
5174*/
5175MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5176 NexusInfo *nexus_info,ExceptionInfo *exception)
5177{
5178 CacheInfo
5179 *cache_info;
5180
5181 MagickBooleanType
5182 status;
5183
5184 /*
5185 Transfer pixels to the cache.
5186 */
5187 assert(image != (Image *) NULL);
5188 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005189 if (image->cache == (Cache) NULL)
5190 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5191 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005192 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005193 if (cache_info->type == UndefinedCache)
5194 return(MagickFalse);
5195 if ((image->clip_mask != (Image *) NULL) &&
5196 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5197 return(MagickFalse);
5198 if ((image->mask != (Image *) NULL) &&
5199 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5200 return(MagickFalse);
5201 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5202 return(MagickTrue);
5203 assert(cache_info->signature == MagickSignature);
5204 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5205 if ((cache_info->active_index_channel != MagickFalse) &&
5206 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5207 return(MagickFalse);
5208 return(status);
5209}
5210
5211/*
5212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5213% %
5214% %
5215% %
5216+ S y n c A u t h e n t i c P i x e l C a c h e %
5217% %
5218% %
5219% %
5220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5221%
5222% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5223% or disk cache. The method returns MagickTrue if the pixel region is synced,
5224% otherwise MagickFalse.
5225%
5226% The format of the SyncAuthenticPixelsCache() method is:
5227%
5228% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5229% ExceptionInfo *exception)
5230%
5231% A description of each parameter follows:
5232%
5233% o image: the image.
5234%
5235% o exception: return any errors or warnings in this structure.
5236%
5237*/
5238static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5239 ExceptionInfo *exception)
5240{
5241 CacheInfo
5242 *cache_info;
5243
cristy5c9e6f22010-09-17 17:31:01 +00005244 const int
5245 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005246
cristye7cc7cf2010-09-21 13:26:47 +00005247 assert(image != (Image *) NULL);
5248 assert(image->signature == MagickSignature);
5249 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005250 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005251 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005252 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005253 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5254 exception));
cristy3ed852e2009-09-05 21:47:34 +00005255}
5256
5257/*
5258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5259% %
5260% %
5261% %
5262% S y n c A u t h e n t i c P i x e l s %
5263% %
5264% %
5265% %
5266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5267%
5268% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5269% The method returns MagickTrue if the pixel region is flushed, otherwise
5270% MagickFalse.
5271%
5272% The format of the SyncAuthenticPixels() method is:
5273%
5274% MagickBooleanType SyncAuthenticPixels(Image *image,
5275% ExceptionInfo *exception)
5276%
5277% A description of each parameter follows:
5278%
5279% o image: the image.
5280%
5281% o exception: return any errors or warnings in this structure.
5282%
5283*/
5284MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5285 ExceptionInfo *exception)
5286{
5287 CacheInfo
5288 *cache_info;
5289
cristy2036f5c2010-09-19 21:18:17 +00005290 const int
5291 id = GetOpenMPThreadId();
5292
cristy3ed852e2009-09-05 21:47:34 +00005293 assert(image != (Image *) NULL);
5294 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005295 assert(image->cache != (Cache) NULL);
5296 cache_info=(CacheInfo *) image->cache;
5297 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005298 if (cache_info->methods.sync_authentic_pixels_handler !=
5299 (SyncAuthenticPixelsHandler) NULL)
5300 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005301 assert(id < (int) cache_info->number_threads);
5302 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5303 exception));
cristy3ed852e2009-09-05 21:47:34 +00005304}
5305
5306/*
5307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5308% %
5309% %
5310% %
5311+ W r i t e P i x e l C a c h e I n d e x e s %
5312% %
5313% %
5314% %
5315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5316%
5317% WritePixelCacheIndexes() writes the colormap indexes to the specified
5318% region of the pixel cache.
5319%
5320% The format of the WritePixelCacheIndexes() method is:
5321%
5322% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5323% NexusInfo *nexus_info,ExceptionInfo *exception)
5324%
5325% A description of each parameter follows:
5326%
5327% o cache_info: the pixel cache.
5328%
5329% o nexus_info: the cache nexus to write the colormap indexes.
5330%
5331% o exception: return any errors or warnings in this structure.
5332%
5333*/
5334static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5335 NexusInfo *nexus_info,ExceptionInfo *exception)
5336{
5337 MagickOffsetType
5338 count,
5339 offset;
5340
5341 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005342 extent,
5343 length;
cristy3ed852e2009-09-05 21:47:34 +00005344
5345 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005346 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005347
cristybb503372010-05-27 20:51:26 +00005348 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005349 y;
5350
cristybb503372010-05-27 20:51:26 +00005351 size_t
cristy3ed852e2009-09-05 21:47:34 +00005352 rows;
5353
cristy3ed852e2009-09-05 21:47:34 +00005354 if (cache_info->active_index_channel == MagickFalse)
5355 return(MagickFalse);
5356 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5357 return(MagickTrue);
5358 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5359 nexus_info->region.x;
5360 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5361 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005362 extent=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005363 p=nexus_info->indexes;
5364 switch (cache_info->type)
5365 {
5366 case MemoryCache:
5367 case MapCache:
5368 {
5369 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005370 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005371
5372 /*
5373 Write indexes to memory.
5374 */
cristydd341db2010-03-04 19:06:38 +00005375 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005376 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005377 {
cristy48078b12010-09-23 17:11:01 +00005378 length=extent;
cristydd341db2010-03-04 19:06:38 +00005379 rows=1UL;
5380 }
cristy3ed852e2009-09-05 21:47:34 +00005381 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005382 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005383 {
cristy8f036fe2010-09-18 02:02:00 +00005384 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005385 p+=nexus_info->region.width;
5386 q+=cache_info->columns;
5387 }
5388 break;
5389 }
5390 case DiskCache:
5391 {
5392 /*
5393 Write indexes to disk.
5394 */
5395 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5396 {
5397 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5398 cache_info->cache_filename);
5399 return(MagickFalse);
5400 }
cristydd341db2010-03-04 19:06:38 +00005401 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005402 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005403 {
cristy48078b12010-09-23 17:11:01 +00005404 length=extent;
cristydd341db2010-03-04 19:06:38 +00005405 rows=1UL;
5406 }
cristy48078b12010-09-23 17:11:01 +00005407 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005408 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005409 {
cristy48078b12010-09-23 17:11:01 +00005410 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5411 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5412 p);
cristy3ed852e2009-09-05 21:47:34 +00005413 if ((MagickSizeType) count < length)
5414 break;
5415 p+=nexus_info->region.width;
5416 offset+=cache_info->columns;
5417 }
cristybb503372010-05-27 20:51:26 +00005418 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005419 {
5420 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5421 cache_info->cache_filename);
5422 return(MagickFalse);
5423 }
5424 break;
5425 }
5426 default:
5427 break;
5428 }
5429 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005430 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005431 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005432 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005433 nexus_info->region.width,(double) nexus_info->region.height,(double)
5434 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005435 return(MagickTrue);
5436}
5437
5438/*
5439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5440% %
5441% %
5442% %
5443+ W r i t e C a c h e P i x e l s %
5444% %
5445% %
5446% %
5447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5448%
5449% WritePixelCachePixels() writes image pixels to the specified region of the
5450% pixel cache.
5451%
5452% The format of the WritePixelCachePixels() method is:
5453%
5454% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5455% NexusInfo *nexus_info,ExceptionInfo *exception)
5456%
5457% A description of each parameter follows:
5458%
5459% o cache_info: the pixel cache.
5460%
5461% o nexus_info: the cache nexus to write the pixels.
5462%
5463% o exception: return any errors or warnings in this structure.
5464%
5465*/
5466static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5467 NexusInfo *nexus_info,ExceptionInfo *exception)
5468{
5469 MagickOffsetType
5470 count,
5471 offset;
5472
5473 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005474 extent,
5475 length;
cristy3ed852e2009-09-05 21:47:34 +00005476
cristy3ed852e2009-09-05 21:47:34 +00005477 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005478 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005479
cristybb503372010-05-27 20:51:26 +00005480 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005481 y;
5482
cristybb503372010-05-27 20:51:26 +00005483 size_t
cristy3ed852e2009-09-05 21:47:34 +00005484 rows;
5485
cristy3ed852e2009-09-05 21:47:34 +00005486 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5487 return(MagickTrue);
5488 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5489 nexus_info->region.x;
5490 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5491 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005492 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005493 p=nexus_info->pixels;
5494 switch (cache_info->type)
5495 {
5496 case MemoryCache:
5497 case MapCache:
5498 {
5499 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005500 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005501
5502 /*
5503 Write pixels to memory.
5504 */
cristydd341db2010-03-04 19:06:38 +00005505 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005506 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005507 {
cristy48078b12010-09-23 17:11:01 +00005508 length=extent;
cristydd341db2010-03-04 19:06:38 +00005509 rows=1UL;
5510 }
cristy3ed852e2009-09-05 21:47:34 +00005511 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005512 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005513 {
cristy8f036fe2010-09-18 02:02:00 +00005514 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005515 p+=nexus_info->region.width;
5516 q+=cache_info->columns;
5517 }
5518 break;
5519 }
5520 case DiskCache:
5521 {
5522 /*
5523 Write pixels to disk.
5524 */
5525 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5526 {
5527 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5528 cache_info->cache_filename);
5529 return(MagickFalse);
5530 }
cristydd341db2010-03-04 19:06:38 +00005531 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005532 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005533 {
cristy48078b12010-09-23 17:11:01 +00005534 length=extent;
cristydd341db2010-03-04 19:06:38 +00005535 rows=1UL;
5536 }
cristybb503372010-05-27 20:51:26 +00005537 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005538 {
5539 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5540 sizeof(*p),length,(const unsigned char *) p);
5541 if ((MagickSizeType) count < length)
5542 break;
5543 p+=nexus_info->region.width;
5544 offset+=cache_info->columns;
5545 }
cristybb503372010-05-27 20:51:26 +00005546 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005547 {
5548 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5549 cache_info->cache_filename);
5550 return(MagickFalse);
5551 }
5552 break;
5553 }
5554 default:
5555 break;
5556 }
5557 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005558 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005559 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005560 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005561 nexus_info->region.width,(double) nexus_info->region.height,(double)
5562 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005563 return(MagickTrue);
5564}