blob: 195c3a05512f51d73122d6bfd82ce1b8af68d5bc [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
59#include "magick/quantum.h"
60#include "magick/random_.h"
61#include "magick/resource_.h"
62#include "magick/semaphore.h"
63#include "magick/splay-tree.h"
64#include "magick/string_.h"
65#include "magick/thread-private.h"
66#include "magick/utility.h"
67#if defined(MAGICKCORE_ZLIB_DELEGATE)
68#include "zlib.h"
69#endif
70
71/*
cristy30097232010-07-01 02:16:30 +000072 Define declarations.
73*/
74#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
75
76/*
cristy3ed852e2009-09-05 21:47:34 +000077 Typedef declarations.
78*/
79typedef struct _MagickModulo
80{
cristybb503372010-05-27 20:51:26 +000081 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000082 quotient,
83 remainder;
84} MagickModulo;
85
86struct _NexusInfo
87{
88 MagickBooleanType
89 mapped;
90
91 RectangleInfo
92 region;
93
94 MagickSizeType
95 length;
96
97 PixelPacket
98 *cache,
99 *pixels;
100
101 IndexPacket
102 *indexes;
103
cristybb503372010-05-27 20:51:26 +0000104 size_t
cristy3ed852e2009-09-05 21:47:34 +0000105 signature;
106};
107
108/*
109 Forward declarations.
110*/
111#if defined(__cplusplus) || defined(c_plusplus)
112extern "C" {
113#endif
114
115static const IndexPacket
116 *GetVirtualIndexesFromCache(const Image *);
117
118static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 *GetVirtualPixelsCache(const Image *);
122
123static MagickBooleanType
cristy09c1c4d2010-06-30 18:23:16 +0000124 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
125 PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000126 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristybb503372010-05-27 20:51:26 +0000127 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000128 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
129 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
130 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
131 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
132 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
134
135static PixelPacket
cristybb503372010-05-27 20:51:26 +0000136 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
137 const size_t,ExceptionInfo *),
138 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000140 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000141 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000142
143#if defined(__cplusplus) || defined(c_plusplus)
144}
145#endif
146
147/*
148 Global declarations.
149*/
150static volatile MagickBooleanType
151 instantiate_cache = MagickFalse;
152
153static SemaphoreInfo
154 *cache_semaphore = (SemaphoreInfo *) NULL;
155
156static SplayTreeInfo
157 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000158
159/*
160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
161% %
162% %
163% %
164+ A c q u i r e P i x e l C a c h e %
165% %
166% %
167% %
168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169%
170% AcquirePixelCache() acquires a pixel cache.
171%
172% The format of the AcquirePixelCache() method is:
173%
cristybb503372010-05-27 20:51:26 +0000174% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000175%
176% A description of each parameter follows:
177%
178% o number_threads: the number of nexus threads.
179%
180*/
cristybb503372010-05-27 20:51:26 +0000181MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000182{
183 CacheInfo
184 *cache_info;
185
186 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
187 if (cache_info == (CacheInfo *) NULL)
188 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
189 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
190 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000191 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000192 cache_info->colorspace=RGBColorspace;
193 cache_info->file=(-1);
194 cache_info->id=GetMagickThreadId();
195 cache_info->number_threads=number_threads;
196 if (number_threads == 0)
197 cache_info->number_threads=GetOpenMPMaximumThreads();
198 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
199 if (cache_info->nexus_info == (NexusInfo **) NULL)
200 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
201 GetPixelCacheMethods(&cache_info->methods);
202 cache_info->reference_count=1;
203 cache_info->semaphore=AllocateSemaphoreInfo();
204 cache_info->disk_semaphore=AllocateSemaphoreInfo();
205 cache_info->debug=IsEventLogging();
206 cache_info->signature=MagickSignature;
207 if ((cache_resources == (SplayTreeInfo *) NULL) &&
208 (instantiate_cache == MagickFalse))
209 {
cristy4e1dff62009-10-25 20:36:03 +0000210 if (cache_semaphore == (SemaphoreInfo *) NULL)
211 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000212 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000213 if ((cache_resources == (SplayTreeInfo *) NULL) &&
214 (instantiate_cache == MagickFalse))
215 {
216 cache_resources=NewSplayTree((int (*)(const void *,const void *))
217 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
218 instantiate_cache=MagickTrue;
219 }
cristyf84a1932010-01-03 18:00:18 +0000220 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000221 }
222 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
223 return((Cache ) cache_info);
224}
225
226/*
227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228% %
229% %
230% %
231% A c q u i r e P i x e l C a c h e N e x u s %
232% %
233% %
234% %
235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236%
237% AcquirePixelCacheNexus() allocates the NexusInfo structure.
238%
239% The format of the AcquirePixelCacheNexus method is:
240%
cristybb503372010-05-27 20:51:26 +0000241% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000242%
243% A description of each parameter follows:
244%
245% o number_threads: the number of nexus threads.
246%
247*/
248MagickExport NexusInfo **AcquirePixelCacheNexus(
cristybb503372010-05-27 20:51:26 +0000249 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000250{
cristybb503372010-05-27 20:51:26 +0000251 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000252 i;
253
254 NexusInfo
255 **nexus_info;
256
257 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
264 if (nexus_info[i] == (NexusInfo *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267 nexus_info[i]->signature=MagickSignature;
268 }
269 return(nexus_info);
270}
271
272/*
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274% %
275% %
276% %
cristyd43a46b2010-01-21 02:13:41 +0000277+ A c q u i r e P i x e l C a c h e P i x e l s %
278% %
279% %
280% %
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282%
283% AcquirePixelCachePixels() returns the pixels associated with the specified
284% image.
285%
286% The format of the AcquirePixelCachePixels() method is:
287%
288% const void *AcquirePixelCachePixels(const Image *image,
289% MagickSizeType *length,ExceptionInfo *exception)
290%
291% A description of each parameter follows:
292%
293% o image: the image.
294%
295% o length: the pixel cache length.
296%
297% o exception: return any errors or warnings in this structure.
298%
299*/
300MagickExport const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
302{
303 CacheInfo
304 *cache_info;
305
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickSignature);
308 if (image->debug != MagickFalse)
309 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
310 assert(exception != (ExceptionInfo *) NULL);
311 assert(exception->signature == MagickSignature);
312 assert(image->cache != (Cache) NULL);
313 cache_info=(CacheInfo *) image->cache;
314 assert(cache_info->signature == MagickSignature);
315 *length=0;
316 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
317 return((const void *) NULL);
318 *length=cache_info->length;
319 return((const void *) cache_info->pixels);
320}
321
322/*
323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324% %
325% %
326% %
cristyf34a1452009-10-24 22:29:27 +0000327+ C a c h e C o m p o n e n t G e n e s i s %
328% %
329% %
330% %
331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332%
333% CacheComponentGenesis() instantiates the cache component.
334%
335% The format of the CacheComponentGenesis method is:
336%
337% MagickBooleanType CacheComponentGenesis(void)
338%
339*/
340MagickExport MagickBooleanType CacheComponentGenesis(void)
341{
cristy165b6092009-10-26 13:52:10 +0000342 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000343 return(MagickTrue);
344}
345
346/*
347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348% %
349% %
350% %
351+ C a c h e C o m p o n e n t T e r m i n u s %
352% %
353% %
354% %
355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356%
357% CacheComponentTerminus() destroys the cache component.
358%
359% The format of the CacheComponentTerminus() method is:
360%
361% CacheComponentTerminus(void)
362%
363*/
364MagickExport void CacheComponentTerminus(void)
365{
cristy18b17442009-10-25 18:36:48 +0000366 if (cache_semaphore == (SemaphoreInfo *) NULL)
367 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000368 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000369 if (cache_resources != (SplayTreeInfo *) NULL)
370 cache_resources=DestroySplayTree(cache_resources);
371 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000372 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000373 DestroySemaphoreInfo(&cache_semaphore);
374}
375
376/*
377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378% %
379% %
380% %
cristy3ed852e2009-09-05 21:47:34 +0000381+ C l i p P i x e l C a c h e N e x u s %
382% %
383% %
384% %
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386%
387% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
388% mask. The method returns MagickTrue if the pixel region is clipped,
389% otherwise MagickFalse.
390%
391% The format of the ClipPixelCacheNexus() method is:
392%
393% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
394% ExceptionInfo *exception)
395%
396% A description of each parameter follows:
397%
398% o image: the image.
399%
400% o nexus_info: the cache nexus to clip.
401%
402% o exception: return any errors or warnings in this structure.
403%
404*/
405static MagickBooleanType ClipPixelCacheNexus(Image *image,
406 NexusInfo *nexus_info,ExceptionInfo *exception)
407{
408 CacheInfo
409 *cache_info;
410
411 MagickSizeType
412 number_pixels;
413
414 NexusInfo
415 **clip_nexus,
416 **image_nexus;
417
418 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
421 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict nexus_indexes,
423 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000424
cristybb503372010-05-27 20:51:26 +0000425 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000426 i;
427
428 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000429 *restrict p,
430 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000431
432 /*
433 Apply clip mask.
434 */
435 if (image->debug != MagickFalse)
436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
437 if (image->clip_mask == (Image *) NULL)
438 return(MagickFalse);
439 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
440 if (cache_info == (Cache) NULL)
441 return(MagickFalse);
442 image_nexus=AcquirePixelCacheNexus(1);
443 clip_nexus=AcquirePixelCacheNexus(1);
444 if ((image_nexus == (NexusInfo **) NULL) ||
445 (clip_nexus == (NexusInfo **) NULL))
446 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
447 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
448 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
449 exception);
450 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
451 q=nexus_info->pixels;
452 nexus_indexes=nexus_info->indexes;
453 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
454 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
455 nexus_info->region.height,clip_nexus[0],exception);
456 number_pixels=(MagickSizeType) nexus_info->region.width*
457 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000458 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000459 {
460 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
461 break;
462 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
463 {
cristyce70c172010-01-07 17:15:30 +0000464 SetRedPixelComponent(q,GetRedPixelComponent(p));
465 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
466 SetBluePixelComponent(q,GetBluePixelComponent(p));
467 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000468 if (cache_info->active_index_channel != MagickFalse)
469 nexus_indexes[i]=indexes[i];
470 }
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% %
530+ C l o n e P i x e l C a c h e N e x u s %
531% %
532% %
533% %
534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
535%
536% ClonePixelCacheNexus() clones the source cache nexus to the destination
537% nexus.
538%
539% The format of the ClonePixelCacheNexus() method is:
540%
541% MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
542% CacheInfo *source,ExceptionInfo *exception)
543%
544% A description of each parameter follows:
545%
546% o destination: the destination cache nexus.
547%
548% o source: the source cache nexus.
549%
550% o exception: return any errors or warnings in this structure.
551%
552*/
553
554static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
555 NexusInfo *nexus_info,ExceptionInfo *exception)
556{
557 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
558 return(MagickFalse);
559 nexus_info->mapped=MagickFalse;
560 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
561 nexus_info->length);
562 if (nexus_info->cache == (PixelPacket *) NULL)
563 {
564 nexus_info->mapped=MagickTrue;
565 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
566 nexus_info->length);
567 }
568 if (nexus_info->cache == (PixelPacket *) NULL)
569 {
570 (void) ThrowMagickException(exception,GetMagickModule(),
571 ResourceLimitError,"MemoryAllocationFailed","`%s'",
572 cache_info->filename);
573 return(MagickFalse);
574 }
575 return(MagickTrue);
576}
577
578static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
579 CacheInfo *source,ExceptionInfo *exception)
580{
581 MagickBooleanType
582 status;
583
584 MagickSizeType
585 number_pixels;
586
cristybb503372010-05-27 20:51:26 +0000587 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000588 i;
589
590 register const NexusInfo
591 *p;
592
593 register NexusInfo
594 *q;
595
596 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000597 for (i=0; i < (ssize_t) source->number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000598 {
599 p=source->nexus_info[i];
600 q=destination->nexus_info[i];
601 q->mapped=p->mapped;
602 q->region=p->region;
603 q->length=p->length;
604 q->cache=p->cache;
605 q->pixels=p->pixels;
606 q->indexes=p->indexes;
607 if (p->cache != (PixelPacket *) NULL)
608 {
609 status=AcquireCacheNexusPixels(source,q,exception);
610 if (status != MagickFalse)
611 {
612 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
613 q->pixels=q->cache;
614 q->indexes=(IndexPacket *) NULL;
615 number_pixels=(MagickSizeType) q->region.width*q->region.height;
616 if (p->indexes != (IndexPacket *) NULL)
617 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
618 }
619 }
620 }
621 return(status);
622}
623
624/*
625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
626% %
627% %
628% %
cristy60c44a82009-10-07 00:58:49 +0000629+ 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 +0000630% %
631% %
632% %
633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
634% ClonePixelCachePixels() clones the source pixel cache to the destination
635% cache.
636%
637% The format of the ClonePixelCachePixels() method is:
638%
639% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
640% CacheInfo *source_info,ExceptionInfo *exception)
641%
642% A description of each parameter follows:
643%
644% o cache_info: the pixel cache.
645%
646% o source_info: the source pixel cache.
647%
648% o exception: return any errors or warnings in this structure.
649%
650*/
651
652static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
653{
654 int
655 status;
656
cristy5ee247a2010-02-12 15:42:34 +0000657 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000658 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000659 if (cache_info->file != -1)
660 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000661 cache_info->file=(-1);
662 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000663 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000664 return(status == -1 ? MagickFalse : MagickTrue);
665}
666
667static void LimitPixelCacheDescriptors(void)
668{
669 register CacheInfo
670 *p,
671 *q;
672
673 /*
674 Limit # of open file descriptors.
675 */
676 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
677 return;
cristyf84a1932010-01-03 18:00:18 +0000678 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000679 if (cache_resources == (SplayTreeInfo *) NULL)
680 {
cristyf84a1932010-01-03 18:00:18 +0000681 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000682 return;
683 }
684 ResetSplayTreeIterator(cache_resources);
685 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
686 while (p != (CacheInfo *) NULL)
687 {
688 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000689 break;
cristy3ed852e2009-09-05 21:47:34 +0000690 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
691 }
692 for (q=p; p != (CacheInfo *) NULL; )
693 {
694 if ((p->type == DiskCache) && (p->file != -1) &&
695 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000696 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000697 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
698 }
699 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000700 {
701 /*
702 Close least recently used cache.
703 */
704 (void) close(q->file);
705 q->file=(-1);
706 }
cristyf84a1932010-01-03 18:00:18 +0000707 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000708}
709
710static inline MagickSizeType MagickMax(const MagickSizeType x,
711 const MagickSizeType y)
712{
713 if (x > y)
714 return(x);
715 return(y);
716}
717
718static inline MagickSizeType MagickMin(const MagickSizeType x,
719 const MagickSizeType y)
720{
721 if (x < y)
722 return(x);
723 return(y);
724}
725
726static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
727 const MapMode mode)
728{
729 int
730 file;
731
732 /*
733 Open pixel cache on disk.
734 */
cristyf84a1932010-01-03 18:00:18 +0000735 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000736 if (cache_info->file != -1)
737 {
cristyf84a1932010-01-03 18:00:18 +0000738 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000739 return(MagickTrue); /* cache already open */
740 }
741 LimitPixelCacheDescriptors();
742 if (*cache_info->cache_filename == '\0')
743 file=AcquireUniqueFileResource(cache_info->cache_filename);
744 else
745 switch (mode)
746 {
747 case ReadMode:
748 {
749 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
750 break;
751 }
752 case WriteMode:
753 {
754 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
755 O_EXCL,S_MODE);
756 if (file == -1)
757 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
758 break;
759 }
760 case IOMode:
761 default:
762 {
763 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
764 O_EXCL,S_MODE);
765 if (file == -1)
766 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
767 break;
768 }
769 }
770 if (file == -1)
771 {
cristyf84a1932010-01-03 18:00:18 +0000772 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000773 return(MagickFalse);
774 }
775 (void) AcquireMagickResource(FileResource,1);
776 cache_info->file=file;
777 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000778 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000779 return(MagickTrue);
780}
781
782static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
783 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000784 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000785{
786 register MagickOffsetType
787 i;
788
789 ssize_t
790 count;
791
cristy08a88202010-03-04 19:18:05 +0000792 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000793#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000794 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000795 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
796 {
cristyf84a1932010-01-03 18:00:18 +0000797 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000798 return((MagickOffsetType) -1);
799 }
800#endif
801 count=0;
802 for (i=0; i < (MagickOffsetType) length; i+=count)
803 {
804#if !defined(MAGICKCORE_HAVE_PREAD)
805 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
806 (MagickSizeType) SSIZE_MAX));
807#else
808 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
809 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
810#endif
811 if (count > 0)
812 continue;
813 count=0;
814 if (errno != EINTR)
815 {
816 i=(-1);
817 break;
818 }
819 }
820#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000821 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000822#endif
823 return(i);
824}
825
826static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
827 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000828 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000829{
830 register MagickOffsetType
831 i;
832
833 ssize_t
834 count;
835
cristy08a88202010-03-04 19:18:05 +0000836 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000837#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000838 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000839 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
840 {
cristyf84a1932010-01-03 18:00:18 +0000841 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000842 return((MagickOffsetType) -1);
843 }
844#endif
845 count=0;
846 for (i=0; i < (MagickOffsetType) length; i+=count)
847 {
848#if !defined(MAGICKCORE_HAVE_PWRITE)
849 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
850 (MagickSizeType) SSIZE_MAX));
851#else
852 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
853 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
854#endif
855 if (count > 0)
856 continue;
857 count=0;
858 if (errno != EINTR)
859 {
860 i=(-1);
861 break;
862 }
863 }
864#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000865 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000866#endif
867 return(i);
868}
869
870static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
871 CacheInfo *cache_info,ExceptionInfo *exception)
872{
873 MagickOffsetType
874 count,
875 offset,
876 source_offset;
877
878 MagickSizeType
879 length;
880
cristybb503372010-05-27 20:51:26 +0000881 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000882 y;
883
884 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000885 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000886
cristybb503372010-05-27 20:51:26 +0000887 size_t
cristy3ed852e2009-09-05 21:47:34 +0000888 columns,
889 rows;
890
891 if (cache_info->debug != MagickFalse)
892 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
893 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
894 {
895 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
896 clone_info->cache_filename);
897 return(MagickFalse);
898 }
899 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
900 {
901 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
902 cache_info->cache_filename);
903 return(MagickFalse);
904 }
cristybb503372010-05-27 20:51:26 +0000905 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
906 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000907 if ((clone_info->active_index_channel != MagickFalse) &&
908 (cache_info->active_index_channel != MagickFalse))
909 {
910 register IndexPacket
911 *indexes;
912
913 /*
914 Clone cache indexes.
915 */
916 length=MagickMax(clone_info->columns,cache_info->columns)*
917 sizeof(*indexes);
918 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
919 if (indexes == (IndexPacket *) NULL)
920 {
921 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
922 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
923 return(MagickFalse);
924 }
925 (void) ResetMagickMemory(indexes,0,(size_t) length);
926 length=columns*sizeof(*indexes);
927 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
928 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
929 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
930 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000931 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000932 {
933 source_offset-=cache_info->columns*sizeof(*indexes);
934 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
935 length,(unsigned char *) indexes);
936 if ((MagickSizeType) count != length)
937 break;
938 offset-=clone_info->columns*sizeof(*indexes);
939 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
940 (unsigned char *) indexes);
941 if ((MagickSizeType) count != length)
942 break;
943 }
cristybb503372010-05-27 20:51:26 +0000944 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000945 {
946 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
947 ThrowFileException(exception,CacheError,"UnableToCloneCache",
948 cache_info->cache_filename);
949 return(MagickFalse);
950 }
951 if (clone_info->columns > cache_info->columns)
952 {
953 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
954 (void) ResetMagickMemory(indexes,0,(size_t) length);
955 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
956 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000957 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000958 {
959 offset-=clone_info->columns*sizeof(*indexes);
960 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
961 length,(unsigned char *) indexes);
962 if ((MagickSizeType) count != length)
963 break;
964 }
cristybb503372010-05-27 20:51:26 +0000965 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
967 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
968 ThrowFileException(exception,CacheError,"UnableToCloneCache",
969 cache_info->cache_filename);
970 return(MagickFalse);
971 }
972 }
973 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
974 }
975 /*
976 Clone cache pixels.
977 */
978 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
979 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
980 if (pixels == (PixelPacket *) NULL)
981 {
982 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
983 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
984 return(MagickFalse);
985 }
986 (void) ResetMagickMemory(pixels,0,(size_t) length);
987 length=columns*sizeof(*pixels);
988 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
989 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 source_offset-=cache_info->columns*sizeof(*pixels);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
994 length,(unsigned char *) pixels);
995 if ((MagickSizeType) count != length)
996 break;
997 offset-=clone_info->columns*sizeof(*pixels);
998 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
999 (unsigned char *) pixels);
1000 if ((MagickSizeType) count != length)
1001 break;
1002 }
cristybb503372010-05-27 20:51:26 +00001003 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001004 {
1005 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1006 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1007 cache_info->cache_filename);
1008 return(MagickFalse);
1009 }
1010 if (clone_info->columns > cache_info->columns)
1011 {
1012 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1013 sizeof(*pixels);
1014 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1015 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001016 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001017 {
1018 offset-=clone_info->columns*sizeof(*pixels);
1019 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1020 (unsigned char *) pixels);
1021 if ((MagickSizeType) count != length)
1022 break;
1023 }
cristybb503372010-05-27 20:51:26 +00001024 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001025 {
1026 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1027 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1028 cache_info->cache_filename);
1029 return(MagickFalse);
1030 }
1031 }
1032 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1033 return(MagickTrue);
1034}
1035
1036static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1037 CacheInfo *cache_info,ExceptionInfo *exception)
1038{
1039 MagickOffsetType
1040 count,
1041 offset;
1042
1043 MagickSizeType
1044 length;
1045
cristybb503372010-05-27 20:51:26 +00001046 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001047 y;
1048
1049 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001050 *restrict pixels,
1051 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001052
cristybb503372010-05-27 20:51:26 +00001053 size_t
cristy3ed852e2009-09-05 21:47:34 +00001054 columns,
1055 rows;
1056
1057 if (cache_info->debug != MagickFalse)
1058 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1059 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1060 {
1061 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1062 cache_info->cache_filename);
1063 return(MagickFalse);
1064 }
cristybb503372010-05-27 20:51:26 +00001065 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1066 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001067 if ((clone_info->active_index_channel != MagickFalse) &&
1068 (cache_info->active_index_channel != MagickFalse))
1069 {
1070 register IndexPacket
1071 *indexes,
1072 *q;
1073
1074 /*
1075 Clone cache indexes.
1076 */
1077 length=MagickMax(clone_info->columns,cache_info->columns)*
1078 sizeof(*indexes);
1079 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1080 if (indexes == (IndexPacket *) NULL)
1081 {
1082 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1083 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1084 return(MagickFalse);
1085 }
1086 (void) ResetMagickMemory(indexes,0,(size_t) length);
1087 length=columns*sizeof(IndexPacket);
1088 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1089 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1090 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001091 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001092 {
1093 offset-=cache_info->columns*sizeof(IndexPacket);
1094 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1095 length,(unsigned char *) indexes);
1096 if ((MagickSizeType) count != length)
1097 break;
1098 q-=clone_info->columns;
1099 (void) CopyMagickMemory(q,indexes,(size_t) length);
1100 if ((MagickSizeType) count != length)
1101 break;
1102 }
cristybb503372010-05-27 20:51:26 +00001103 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001104 {
1105 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1106 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1107 cache_info->cache_filename);
1108 return(MagickFalse);
1109 }
1110 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1111 }
1112 /*
1113 Clone cache pixels.
1114 */
1115 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1116 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1117 if (pixels == (PixelPacket *) NULL)
1118 {
1119 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1120 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1121 return(MagickFalse);
1122 }
1123 (void) ResetMagickMemory(pixels,0,(size_t) length);
1124 length=columns*sizeof(*pixels);
1125 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1126 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001127 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001128 {
1129 offset-=cache_info->columns*sizeof(*pixels);
1130 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1131 (unsigned char *) pixels);
1132 if ((MagickSizeType) count != length)
1133 break;
1134 q-=clone_info->columns;
1135 (void) CopyMagickMemory(q,pixels,(size_t) length);
1136 }
cristybb503372010-05-27 20:51:26 +00001137 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001138 {
1139 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1140 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1141 cache_info->cache_filename);
1142 return(MagickFalse);
1143 }
1144 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1145 return(MagickTrue);
1146}
1147
1148static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1149 CacheInfo *cache_info,ExceptionInfo *exception)
1150{
1151 MagickOffsetType
1152 count,
1153 offset;
1154
1155 MagickSizeType
1156 length;
1157
cristybb503372010-05-27 20:51:26 +00001158 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001159 y;
1160
1161 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001162 *restrict p,
1163 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001164
cristybb503372010-05-27 20:51:26 +00001165 size_t
cristy3ed852e2009-09-05 21:47:34 +00001166 columns,
1167 rows;
1168
1169 if (cache_info->debug != MagickFalse)
1170 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1171 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1172 {
1173 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1174 clone_info->cache_filename);
1175 return(MagickFalse);
1176 }
cristybb503372010-05-27 20:51:26 +00001177 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1178 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001179 if ((clone_info->active_index_channel != MagickFalse) &&
1180 (cache_info->active_index_channel != MagickFalse))
1181 {
1182 register IndexPacket
1183 *p,
1184 *indexes;
1185
1186 /*
1187 Clone cache indexes.
1188 */
1189 length=MagickMax(clone_info->columns,cache_info->columns)*
1190 sizeof(*indexes);
1191 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1192 if (indexes == (IndexPacket *) NULL)
1193 {
1194 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1195 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1196 return(MagickFalse);
1197 }
1198 (void) ResetMagickMemory(indexes,0,(size_t) length);
1199 length=columns*sizeof(*indexes);
1200 p=cache_info->indexes+cache_info->columns*rows;
1201 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1202 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001203 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001204 {
1205 p-=cache_info->columns;
1206 (void) CopyMagickMemory(indexes,p,(size_t) length);
1207 offset-=clone_info->columns*sizeof(*indexes);
1208 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1209 (unsigned char *) indexes);
1210 if ((MagickSizeType) count != length)
1211 break;
1212 }
cristybb503372010-05-27 20:51:26 +00001213 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001214 {
1215 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1216 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1217 cache_info->cache_filename);
1218 return(MagickFalse);
1219 }
1220 if (clone_info->columns > cache_info->columns)
1221 {
1222 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1223 (void) ResetMagickMemory(indexes,0,(size_t) length);
1224 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1225 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001226 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001227 {
1228 offset-=clone_info->columns*sizeof(*indexes);
1229 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1230 length,(unsigned char *) indexes);
1231 if ((MagickSizeType) count != length)
1232 break;
1233 }
cristybb503372010-05-27 20:51:26 +00001234 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001235 {
1236 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1237 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1238 cache_info->cache_filename);
1239 return(MagickFalse);
1240 }
1241 }
1242 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1243 }
1244 /*
1245 Clone cache pixels.
1246 */
1247 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1248 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1249 if (pixels == (PixelPacket *) NULL)
1250 {
1251 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1252 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1253 return(MagickFalse);
1254 }
1255 (void) ResetMagickMemory(pixels,0,(size_t) length);
1256 length=columns*sizeof(*pixels);
1257 p=cache_info->pixels+cache_info->columns*rows;
1258 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001259 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001260 {
1261 p-=cache_info->columns;
1262 (void) CopyMagickMemory(pixels,p,(size_t) length);
1263 offset-=clone_info->columns*sizeof(*pixels);
1264 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1265 (unsigned char *) pixels);
1266 if ((MagickSizeType) count != length)
1267 break;
1268 }
cristybb503372010-05-27 20:51:26 +00001269 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001270 {
1271 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1272 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1273 cache_info->cache_filename);
1274 return(MagickFalse);
1275 }
1276 if (clone_info->columns > cache_info->columns)
1277 {
1278 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1279 sizeof(*pixels);
1280 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1281 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001282 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001283 {
1284 offset-=clone_info->columns*sizeof(*pixels);
1285 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1286 (unsigned char *) pixels);
1287 if ((MagickSizeType) count != length)
1288 break;
1289 }
cristybb503372010-05-27 20:51:26 +00001290 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001291 {
1292 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1293 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1294 cache_info->cache_filename);
1295 return(MagickFalse);
1296 }
1297 }
1298 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1299 return(MagickTrue);
1300}
1301
1302static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1303 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1304{
cristybb503372010-05-27 20:51:26 +00001305 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001306 y;
1307
1308 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001309 *restrict pixels,
1310 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001311
1312 size_t
1313 length;
1314
cristybb503372010-05-27 20:51:26 +00001315 size_t
cristy3ed852e2009-09-05 21:47:34 +00001316 columns,
1317 rows;
1318
1319 if (cache_info->debug != MagickFalse)
1320 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001321 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1322 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001323 if ((clone_info->active_index_channel != MagickFalse) &&
1324 (cache_info->active_index_channel != MagickFalse))
1325 {
1326 register IndexPacket
1327 *indexes,
1328 *source_indexes;
1329
1330 /*
1331 Clone cache indexes.
1332 */
1333 length=columns*sizeof(*indexes);
1334 if (clone_info->columns == cache_info->columns)
1335 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1336 length*rows);
1337 else
1338 {
1339 source_indexes=cache_info->indexes+cache_info->columns*rows;
1340 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001341 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001342 {
1343 source_indexes-=cache_info->columns;
1344 indexes-=clone_info->columns;
1345 (void) CopyMagickMemory(indexes,source_indexes,length);
1346 }
1347 if (clone_info->columns > cache_info->columns)
1348 {
1349 length=(clone_info->columns-cache_info->columns)*
1350 sizeof(*indexes);
1351 indexes=clone_info->indexes+clone_info->columns*rows+
1352 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001353 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001354 {
1355 indexes-=clone_info->columns;
1356 (void) ResetMagickMemory(indexes,0,length);
1357 }
1358 }
1359 }
1360 }
1361 /*
1362 Clone cache pixels.
1363 */
1364 length=columns*sizeof(*pixels);
1365 if (clone_info->columns == cache_info->columns)
1366 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1367 else
1368 {
1369 source_pixels=cache_info->pixels+cache_info->columns*rows;
1370 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001371 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001372 {
1373 source_pixels-=cache_info->columns;
1374 pixels-=clone_info->columns;
1375 (void) CopyMagickMemory(pixels,source_pixels,length);
1376 }
1377 if (clone_info->columns > cache_info->columns)
1378 {
1379 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1380 pixels=clone_info->pixels+clone_info->columns*rows+
1381 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001382 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001383 {
1384 pixels-=clone_info->columns;
1385 (void) ResetMagickMemory(pixels,0,length);
1386 }
1387 }
1388 }
1389 return(MagickTrue);
1390}
1391
1392static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1393 CacheInfo *cache_info,ExceptionInfo *exception)
1394{
1395 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1396 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1397 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1398 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1399 if (cache_info->type == DiskCache)
1400 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1401 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1402}
1403
1404/*
1405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406% %
1407% %
1408% %
1409+ C l o n e P i x e l C a c h e M e t h o d s %
1410% %
1411% %
1412% %
1413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414%
1415% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1416% another.
1417%
1418% The format of the ClonePixelCacheMethods() method is:
1419%
1420% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1421%
1422% A description of each parameter follows:
1423%
1424% o clone: Specifies a pointer to a Cache structure.
1425%
1426% o cache: the pixel cache.
1427%
1428*/
1429MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1430{
1431 CacheInfo
1432 *cache_info,
1433 *source_info;
1434
1435 assert(clone != (Cache) NULL);
1436 source_info=(CacheInfo *) clone;
1437 assert(source_info->signature == MagickSignature);
1438 if (source_info->debug != MagickFalse)
1439 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1440 source_info->filename);
1441 assert(cache != (Cache) NULL);
1442 cache_info=(CacheInfo *) cache;
1443 assert(cache_info->signature == MagickSignature);
1444 source_info->methods=cache_info->methods;
1445}
1446
1447/*
1448%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1449% %
1450% %
1451% %
1452+ D e s t r o y I m a g e P i x e l C a c h e %
1453% %
1454% %
1455% %
1456%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457%
1458% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1459%
1460% The format of the DestroyImagePixelCache() method is:
1461%
1462% void DestroyImagePixelCache(Image *image)
1463%
1464% A description of each parameter follows:
1465%
1466% o image: the image.
1467%
1468*/
1469static void DestroyImagePixelCache(Image *image)
1470{
1471 assert(image != (Image *) NULL);
1472 assert(image->signature == MagickSignature);
1473 if (image->debug != MagickFalse)
1474 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1475 if (image->cache == (void *) NULL)
1476 return;
1477 image->cache=DestroyPixelCache(image->cache);
1478}
1479
1480/*
1481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1482% %
1483% %
1484% %
1485+ D e s t r o y I m a g e P i x e l s %
1486% %
1487% %
1488% %
1489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1490%
1491% DestroyImagePixels() deallocates memory associated with the pixel cache.
1492%
1493% The format of the DestroyImagePixels() method is:
1494%
1495% void DestroyImagePixels(Image *image)
1496%
1497% A description of each parameter follows:
1498%
1499% o image: the image.
1500%
1501*/
1502MagickExport void DestroyImagePixels(Image *image)
1503{
1504 CacheInfo
1505 *cache_info;
1506
1507 assert(image != (const Image *) NULL);
1508 assert(image->signature == MagickSignature);
1509 if (image->debug != MagickFalse)
1510 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1511 assert(image->cache != (Cache) NULL);
1512 cache_info=(CacheInfo *) image->cache;
1513 assert(cache_info->signature == MagickSignature);
1514 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1515 return;
1516 cache_info->methods.destroy_pixel_handler(image);
1517}
1518
1519/*
1520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1521% %
1522% %
1523% %
1524+ D e s t r o y P i x e l C a c h e %
1525% %
1526% %
1527% %
1528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1529%
1530% DestroyPixelCache() deallocates memory associated with the pixel cache.
1531%
1532% The format of the DestroyPixelCache() method is:
1533%
1534% Cache DestroyPixelCache(Cache cache)
1535%
1536% A description of each parameter follows:
1537%
1538% o cache: the pixel cache.
1539%
1540*/
1541
1542static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1543{
1544 switch (cache_info->type)
1545 {
1546 case MemoryCache:
1547 {
1548 if (cache_info->mapped == MagickFalse)
1549 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1550 cache_info->pixels);
1551 else
1552 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1553 (size_t) cache_info->length);
1554 RelinquishMagickResource(MemoryResource,cache_info->length);
1555 break;
1556 }
1557 case MapCache:
1558 {
1559 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1560 cache_info->length);
1561 RelinquishMagickResource(MapResource,cache_info->length);
1562 }
1563 case DiskCache:
1564 {
1565 if (cache_info->file != -1)
1566 (void) ClosePixelCacheOnDisk(cache_info);
1567 RelinquishMagickResource(DiskResource,cache_info->length);
1568 break;
1569 }
1570 default:
1571 break;
1572 }
1573 cache_info->type=UndefinedCache;
1574 cache_info->mapped=MagickFalse;
1575 cache_info->indexes=(IndexPacket *) NULL;
1576}
1577
1578MagickExport Cache DestroyPixelCache(Cache cache)
1579{
1580 CacheInfo
1581 *cache_info;
1582
cristy3ed852e2009-09-05 21:47:34 +00001583 assert(cache != (Cache) NULL);
1584 cache_info=(CacheInfo *) cache;
1585 assert(cache_info->signature == MagickSignature);
1586 if (cache_info->debug != MagickFalse)
1587 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1588 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001589 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001590 cache_info->reference_count--;
1591 if (cache_info->reference_count != 0)
1592 {
cristyf84a1932010-01-03 18:00:18 +00001593 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001594 return((Cache) NULL);
1595 }
cristyf84a1932010-01-03 18:00:18 +00001596 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001597 if (cache_resources != (SplayTreeInfo *) NULL)
1598 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001599 if (cache_info->debug != MagickFalse)
1600 {
1601 char
1602 message[MaxTextExtent];
1603
1604 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1605 cache_info->filename);
1606 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1607 }
cristyc2e1bdd2009-09-10 23:43:34 +00001608 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1609 (cache_info->type != DiskCache)))
1610 RelinquishPixelCachePixels(cache_info);
1611 else
1612 {
1613 RelinquishPixelCachePixels(cache_info);
1614 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1615 }
cristy3ed852e2009-09-05 21:47:34 +00001616 *cache_info->cache_filename='\0';
1617 if (cache_info->nexus_info != (NexusInfo **) NULL)
1618 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1619 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001620 if (cache_info->random_info != (RandomInfo *) NULL)
1621 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001622 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1623 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1624 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1625 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001626 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001627 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1628 cache=(Cache) NULL;
1629 return(cache);
1630}
1631
1632/*
1633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1634% %
1635% %
1636% %
1637+ D e s t r o y P i x e l C a c h e N e x u s %
1638% %
1639% %
1640% %
1641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1642%
1643% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1644%
1645% The format of the DestroyPixelCacheNexus() method is:
1646%
1647% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001648% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001649%
1650% A description of each parameter follows:
1651%
1652% o nexus_info: the nexus to destroy.
1653%
1654% o number_threads: the number of nexus threads.
1655%
1656*/
1657
1658static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1659{
1660 if (nexus_info->mapped == MagickFalse)
1661 (void) RelinquishMagickMemory(nexus_info->cache);
1662 else
1663 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1664 nexus_info->cache=(PixelPacket *) NULL;
1665 nexus_info->pixels=(PixelPacket *) NULL;
1666 nexus_info->indexes=(IndexPacket *) NULL;
1667 nexus_info->length=0;
1668 nexus_info->mapped=MagickFalse;
1669}
1670
1671MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001672 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001673{
cristybb503372010-05-27 20:51:26 +00001674 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001675 i;
1676
1677 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001678 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001679 {
1680 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1681 RelinquishCacheNexusPixels(nexus_info[i]);
1682 nexus_info[i]->signature=(~MagickSignature);
1683 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1684 }
1685 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1686 return(nexus_info);
1687}
1688
1689/*
1690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1691% %
1692% %
1693% %
cristy3ed852e2009-09-05 21:47:34 +00001694+ 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 %
1695% %
1696% %
1697% %
1698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1699%
1700% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1701% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1702%
1703% The format of the GetAuthenticIndexesFromCache() method is:
1704%
1705% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1706%
1707% A description of each parameter follows:
1708%
1709% o image: the image.
1710%
1711*/
1712static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1713{
1714 CacheInfo
1715 *cache_info;
1716
1717 IndexPacket
1718 *indexes;
1719
cristybb503372010-05-27 20:51:26 +00001720 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001721 id;
1722
1723 if (image->debug != MagickFalse)
1724 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1725 cache_info=(CacheInfo *) image->cache;
1726 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00001727 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001728 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1729 return(indexes);
1730}
1731
1732/*
1733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734% %
1735% %
1736% %
1737% G e t A u t h e n t i c I n d e x Q u e u e %
1738% %
1739% %
1740% %
1741%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1742%
1743% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1744% indexes associated with the last call to QueueAuthenticPixels() or
1745% GetVirtualPixels(). NULL is returned if the black channel or colormap
1746% indexes are not available.
1747%
1748% The format of the GetAuthenticIndexQueue() method is:
1749%
1750% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1751%
1752% A description of each parameter follows:
1753%
1754% o image: the image.
1755%
1756*/
1757MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1758{
1759 CacheInfo
1760 *cache_info;
1761
1762 assert(image != (const Image *) NULL);
1763 assert(image->signature == MagickSignature);
1764 if (image->debug != MagickFalse)
1765 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1766 assert(image->cache != (Cache) NULL);
1767 cache_info=(CacheInfo *) image->cache;
1768 assert(cache_info->signature == MagickSignature);
1769 if (cache_info->methods.get_authentic_indexes_from_handler ==
1770 (GetAuthenticIndexesFromHandler) NULL)
1771 return((IndexPacket *) NULL);
1772 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1773}
1774
1775/*
1776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1777% %
1778% %
1779% %
1780+ 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 %
1781% %
1782% %
1783% %
1784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1785%
1786% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1787% disk pixel cache as defined by the geometry parameters. A pointer to the
1788% pixels is returned if the pixels are transferred, otherwise a NULL is
1789% returned.
1790%
1791% The format of the GetAuthenticPixelCacheNexus() method is:
1792%
cristybb503372010-05-27 20:51:26 +00001793% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1794% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001795% NexusInfo *nexus_info,ExceptionInfo *exception)
1796%
1797% A description of each parameter follows:
1798%
1799% o image: the image.
1800%
1801% o x,y,columns,rows: These values define the perimeter of a region of
1802% pixels.
1803%
1804% o nexus_info: the cache nexus to return.
1805%
1806% o exception: return any errors or warnings in this structure.
1807%
1808*/
1809
1810static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1811 NexusInfo *nexus_info)
1812{
1813 MagickOffsetType
1814 offset;
1815
cristy73724512010-04-12 14:43:14 +00001816 if (cache_info->type == PingCache)
1817 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001818 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1819 nexus_info->region.x;
1820 if (nexus_info->pixels != (cache_info->pixels+offset))
1821 return(MagickFalse);
1822 return(MagickTrue);
1823}
1824
cristybb503372010-05-27 20:51:26 +00001825MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1826 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001827 NexusInfo *nexus_info,ExceptionInfo *exception)
1828{
1829 CacheInfo
1830 *cache_info;
1831
1832 PixelPacket
1833 *pixels;
1834
1835 /*
1836 Transfer pixels from the cache.
1837 */
1838 assert(image != (Image *) NULL);
1839 assert(image->signature == MagickSignature);
1840 if (image->debug != MagickFalse)
1841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1842 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1843 if (pixels == (PixelPacket *) NULL)
1844 return((PixelPacket *) NULL);
1845 cache_info=(CacheInfo *) image->cache;
1846 assert(cache_info->signature == MagickSignature);
1847 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1848 return(pixels);
1849 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1850 return((PixelPacket *) NULL);
1851 if (cache_info->active_index_channel != MagickFalse)
1852 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1853 return((PixelPacket *) NULL);
1854 return(pixels);
1855}
1856
1857/*
1858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1859% %
1860% %
1861% %
1862+ 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 %
1863% %
1864% %
1865% %
1866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1867%
1868% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1869% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1870%
1871% The format of the GetAuthenticPixelsFromCache() method is:
1872%
1873% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1874%
1875% A description of each parameter follows:
1876%
1877% o image: the image.
1878%
1879*/
1880static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1881{
1882 CacheInfo
1883 *cache_info;
1884
cristybb503372010-05-27 20:51:26 +00001885 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001886 id;
1887
1888 PixelPacket
1889 *pixels;
1890
1891 if (image->debug != MagickFalse)
1892 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1893 cache_info=(CacheInfo *) image->cache;
1894 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00001895 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001896 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1897 return(pixels);
1898}
1899
1900/*
1901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1902% %
1903% %
1904% %
1905% G e t A u t h e n t i c P i x e l Q u e u e %
1906% %
1907% %
1908% %
1909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1910%
1911% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1912% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1913%
1914% The format of the GetAuthenticPixelQueue() method is:
1915%
1916% PixelPacket *GetAuthenticPixelQueue(const Image image)
1917%
1918% A description of each parameter follows:
1919%
1920% o image: the image.
1921%
1922*/
1923MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1924{
1925 CacheInfo
1926 *cache_info;
1927
1928 assert(image != (const Image *) NULL);
1929 assert(image->signature == MagickSignature);
1930 if (image->debug != MagickFalse)
1931 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1932 assert(image->cache != (Cache) NULL);
1933 cache_info=(CacheInfo *) image->cache;
1934 assert(cache_info->signature == MagickSignature);
1935 if (cache_info->methods.get_authentic_pixels_from_handler ==
1936 (GetAuthenticPixelsFromHandler) NULL)
1937 return((PixelPacket *) NULL);
1938 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1939}
1940
1941/*
1942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943% %
1944% %
1945% %
1946% G e t A u t h e n t i c P i x e l s %
1947% %
1948% %
1949% %
1950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1951%
1952% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1953% region is successfully accessed, a pointer to a PixelPacket array
1954% representing the region is returned, otherwise NULL is returned.
1955%
1956% The returned pointer may point to a temporary working copy of the pixels
1957% or it may point to the original pixels in memory. Performance is maximized
1958% if the selected region is part of one row, or one or more full rows, since
1959% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001960% if the image is in memory, or in a memory-mapped file. The returned pointer
1961% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001962%
1963% Pixels accessed via the returned pointer represent a simple array of type
1964% PixelPacket. If the image type is CMYK or if the storage class is
1965% PseduoClass, call GetAuthenticIndexQueue() after invoking
1966% GetAuthenticPixels() to obtain the black color component or colormap indexes
1967% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1968% (and/or IndexPacket) array has been updated, the changes must be saved back
1969% to the underlying image using SyncAuthenticPixels() or they may be lost.
1970%
1971% The format of the GetAuthenticPixels() method is:
1972%
cristy5f959472010-05-27 22:19:46 +00001973% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1974% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001975% ExceptionInfo *exception)
1976%
1977% A description of each parameter follows:
1978%
1979% o image: the image.
1980%
1981% o x,y,columns,rows: These values define the perimeter of a region of
1982% pixels.
1983%
1984% o exception: return any errors or warnings in this structure.
1985%
1986*/
cristybb503372010-05-27 20:51:26 +00001987MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1988 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001989 ExceptionInfo *exception)
1990{
1991 CacheInfo
1992 *cache_info;
1993
1994 PixelPacket
1995 *pixels;
1996
1997 assert(image != (Image *) NULL);
1998 assert(image->signature == MagickSignature);
1999 if (image->debug != MagickFalse)
2000 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2001 assert(image->cache != (Cache) NULL);
2002 cache_info=(CacheInfo *) image->cache;
2003 assert(cache_info->signature == MagickSignature);
2004 if (cache_info->methods.get_authentic_pixels_handler ==
2005 (GetAuthenticPixelsHandler) NULL)
2006 return((PixelPacket *) NULL);
2007 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
2008 rows,exception);
2009 return(pixels);
2010}
2011
2012/*
2013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2014% %
2015% %
2016% %
2017+ G e t A u t h e n t i c P i x e l s C a c h e %
2018% %
2019% %
2020% %
2021%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2022%
2023% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2024% as defined by the geometry parameters. A pointer to the pixels is returned
2025% if the pixels are transferred, otherwise a NULL is returned.
2026%
2027% The format of the GetAuthenticPixelsCache() method is:
2028%
cristybb503372010-05-27 20:51:26 +00002029% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2030% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002031% ExceptionInfo *exception)
2032%
2033% A description of each parameter follows:
2034%
2035% o image: the image.
2036%
2037% o x,y,columns,rows: These values define the perimeter of a region of
2038% pixels.
2039%
2040% o exception: return any errors or warnings in this structure.
2041%
2042*/
cristybb503372010-05-27 20:51:26 +00002043static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2044 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002045 ExceptionInfo *exception)
2046{
2047 CacheInfo
2048 *cache_info;
2049
cristybb503372010-05-27 20:51:26 +00002050 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002051 id;
2052
2053 PixelPacket
2054 *pixels;
2055
2056 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2057 if (cache_info == (Cache) NULL)
2058 return((PixelPacket *) NULL);
2059 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00002060 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002061 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2062 cache_info->nexus_info[id],exception);
2063 return(pixels);
2064}
2065
2066/*
2067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2068% %
2069% %
2070% %
2071+ G e t I m a g e E x t e n t %
2072% %
2073% %
2074% %
2075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2076%
2077% GetImageExtent() returns the extent of the pixels associated with the
2078% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2079%
2080% The format of the GetImageExtent() method is:
2081%
2082% MagickSizeType GetImageExtent(const Image *image)
2083%
2084% A description of each parameter follows:
2085%
2086% o image: the image.
2087%
2088*/
2089MagickExport MagickSizeType GetImageExtent(const Image *image)
2090{
2091 CacheInfo
2092 *cache_info;
2093
cristybb503372010-05-27 20:51:26 +00002094 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002095 id;
2096
2097 MagickSizeType
2098 extent;
2099
2100 assert(image != (Image *) NULL);
2101 assert(image->signature == MagickSignature);
2102 if (image->debug != MagickFalse)
2103 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2104 assert(image->cache != (Cache) NULL);
2105 cache_info=(CacheInfo *) image->cache;
2106 assert(cache_info->signature == MagickSignature);
2107 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00002108 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002109 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2110 return(extent);
2111}
2112
2113/*
2114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2115% %
2116% %
2117% %
2118+ G e t I m a g e P i x e l C a c h e %
2119% %
2120% %
2121% %
2122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2123%
2124% GetImagePixelCache() ensures that there is only a single reference to the
2125% pixel cache to be modified, updating the provided cache pointer to point to
2126% a clone of the original pixel cache if necessary.
2127%
2128% The format of the GetImagePixelCache method is:
2129%
2130% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2131% ExceptionInfo *exception)
2132%
2133% A description of each parameter follows:
2134%
2135% o image: the image.
2136%
2137% o clone: any value other than MagickFalse clones the cache pixels.
2138%
2139% o exception: return any errors or warnings in this structure.
2140%
2141*/
2142
2143static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2144{
2145 CacheInfo
2146 *cache_info;
2147
2148 /*
2149 Does the image match the pixel cache morphology?
2150 */
2151 cache_info=(CacheInfo *) image->cache;
2152 if ((image->storage_class != cache_info->storage_class) ||
2153 (image->colorspace != cache_info->colorspace) ||
2154 (image->columns != cache_info->columns) ||
2155 (image->rows != cache_info->rows) ||
2156 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2157 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2158 return(MagickFalse);
2159 return(MagickTrue);
2160}
2161
2162MagickExport Cache GetImagePixelCache(Image *image,
2163 const MagickBooleanType clone,ExceptionInfo *exception)
2164{
2165 CacheInfo
2166 *cache_info;
2167
cristy3ed852e2009-09-05 21:47:34 +00002168 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002169 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002170 status;
2171
cristy50a10922010-02-15 18:35:25 +00002172 static MagickSizeType
2173 time_limit = 0;
2174
cristy3ed852e2009-09-05 21:47:34 +00002175 if (image->debug != MagickFalse)
2176 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy50a10922010-02-15 18:35:25 +00002177 if (time_limit == 0)
2178 time_limit=GetMagickResourceLimit(TimeResource);
2179 if (time_limit != MagickResourceInfinity)
2180 {
2181 static time_t
2182 cache_timer = 0;
2183
2184 if (cache_timer == 0)
2185 cache_timer=time((time_t *) NULL);
2186 if ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit)
2187 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2188 }
cristyc4f9f132010-03-04 18:50:01 +00002189 status=MagickTrue;
2190 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002191 assert(image->cache != (Cache) NULL);
2192 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002193 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002194 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002195 {
cristyaaa0cb62010-02-15 17:47:27 +00002196 LockSemaphoreInfo(cache_info->semaphore);
2197 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002198 {
cristyaaa0cb62010-02-15 17:47:27 +00002199 Image
2200 clone_image;
2201
2202 CacheInfo
2203 *clone_info;
2204
2205 /*
2206 Clone pixel cache.
2207 */
2208 clone_image=(*image);
2209 clone_image.cache=ClonePixelCache(cache_info);
2210 clone_info=(CacheInfo *) clone_image.cache;
2211 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002212 if (status != MagickFalse)
2213 {
cristyaaa0cb62010-02-15 17:47:27 +00002214 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002215 if (status != MagickFalse)
2216 {
cristyaaa0cb62010-02-15 17:47:27 +00002217 if (clone != MagickFalse)
2218 status=ClonePixelCachePixels(clone_info,cache_info,
2219 exception);
2220 if (status != MagickFalse)
2221 {
2222 destroy=MagickTrue;
2223 image->cache=clone_image.cache;
2224 }
cristy3ed852e2009-09-05 21:47:34 +00002225 }
2226 }
2227 }
cristyaaa0cb62010-02-15 17:47:27 +00002228 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002229 }
cristy4320e0e2009-09-10 15:00:08 +00002230 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002231 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002232 if (status != MagickFalse)
2233 {
2234 /*
2235 Ensure the image matches the pixel cache morphology.
2236 */
2237 image->taint=MagickTrue;
2238 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002239 if (image->colorspace == GRAYColorspace)
2240 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002241 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2242 status=OpenPixelCache(image,IOMode,exception);
2243 }
cristyf84a1932010-01-03 18:00:18 +00002244 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002245 if (status == MagickFalse)
2246 return((Cache) NULL);
2247 return(image->cache);
2248}
2249
2250/*
2251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2252% %
2253% %
2254% %
2255% G e t O n e A u t h e n t i c P i x e l %
2256% %
2257% %
2258% %
2259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2260%
2261% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2262% location. The image background color is returned if an error occurs.
2263%
2264% The format of the GetOneAuthenticPixel() method is:
2265%
cristybb503372010-05-27 20:51:26 +00002266% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2267% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002268%
2269% A description of each parameter follows:
2270%
2271% o image: the image.
2272%
2273% o x,y: These values define the location of the pixel to return.
2274%
2275% o pixel: return a pixel at the specified (x,y) location.
2276%
2277% o exception: return any errors or warnings in this structure.
2278%
2279*/
cristyacbbb7c2010-06-30 18:56:48 +00002280MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2281 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002282{
2283 CacheInfo
2284 *cache_info;
2285
2286 GetOneAuthenticPixelFromHandler
2287 get_one_authentic_pixel_from_handler;
2288
2289 MagickBooleanType
2290 status;
2291
2292 assert(image != (Image *) NULL);
2293 assert(image->signature == MagickSignature);
2294 if (image->debug != MagickFalse)
2295 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2296 assert(image->cache != (Cache) NULL);
2297 cache_info=(CacheInfo *) image->cache;
2298 assert(cache_info->signature == MagickSignature);
2299 *pixel=image->background_color;
2300 get_one_authentic_pixel_from_handler=
2301 cache_info->methods.get_one_authentic_pixel_from_handler;
2302 if (get_one_authentic_pixel_from_handler ==
2303 (GetOneAuthenticPixelFromHandler) NULL)
2304 return(MagickFalse);
2305 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2306 pixel,exception);
2307 return(status);
2308}
2309
2310/*
2311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2312% %
2313% %
2314% %
2315+ 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 %
2316% %
2317% %
2318% %
2319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2320%
2321% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2322% location. The image background color is returned if an error occurs.
2323%
2324% The format of the GetOneAuthenticPixelFromCache() method is:
2325%
2326% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002327% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2328% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002329%
2330% A description of each parameter follows:
2331%
2332% o image: the image.
2333%
2334% o x,y: These values define the location of the pixel to return.
2335%
2336% o pixel: return a pixel at the specified (x,y) location.
2337%
2338% o exception: return any errors or warnings in this structure.
2339%
2340*/
2341static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002342 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002343{
2344 PixelPacket
2345 *pixels;
2346
2347 if (image->debug != MagickFalse)
2348 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2349 *pixel=image->background_color;
2350 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2351 if (pixels == (PixelPacket *) NULL)
2352 return(MagickFalse);
2353 *pixel=(*pixels);
2354 return(MagickTrue);
2355}
2356
2357/*
2358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2359% %
2360% %
2361% %
2362% G e t O n e V i r t u a l M a g i c k P i x e l %
2363% %
2364% %
2365% %
2366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367%
2368% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2369% location. The image background color is returned if an error occurs. If
2370% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2371%
2372% The format of the GetOneVirtualMagickPixel() method is:
2373%
2374% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002375% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002376% ExceptionInfo exception)
2377%
2378% A description of each parameter follows:
2379%
2380% o image: the image.
2381%
2382% o x,y: these values define the location of the pixel to return.
2383%
2384% o pixel: return a pixel at the specified (x,y) location.
2385%
2386% o exception: return any errors or warnings in this structure.
2387%
2388*/
2389MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002390 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2391 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002392{
2393 CacheInfo
2394 *cache_info;
2395
2396 register const IndexPacket
2397 *indexes;
2398
2399 register const PixelPacket
2400 *p;
2401
2402 assert(image != (const Image *) NULL);
2403 assert(image->signature == MagickSignature);
2404 assert(image->cache != (Cache) NULL);
2405 cache_info=(CacheInfo *) image->cache;
2406 assert(cache_info->signature == MagickSignature);
2407 GetMagickPixelPacket(image,pixel);
2408 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2409 exception);
2410 if (p == (const PixelPacket *) NULL)
2411 return(MagickFalse);
2412 indexes=GetVirtualIndexQueue(image);
2413 SetMagickPixelPacket(image,p,indexes,pixel);
2414 return(MagickTrue);
2415}
2416
2417/*
2418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2419% %
2420% %
2421% %
2422% G e t O n e V i r t u a l M e t h o d P i x e l %
2423% %
2424% %
2425% %
2426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2427%
2428% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2429% location as defined by specified pixel method. The image background color
2430% is returned if an error occurs. If you plan to modify the pixel, use
2431% GetOneAuthenticPixel() instead.
2432%
2433% The format of the GetOneVirtualMethodPixel() method is:
2434%
2435% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002436% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2437% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002438%
2439% A description of each parameter follows:
2440%
2441% o image: the image.
2442%
2443% o virtual_pixel_method: the virtual pixel method.
2444%
2445% o x,y: These values define the location of the pixel to return.
2446%
2447% o pixel: return a pixel at the specified (x,y) location.
2448%
2449% o exception: return any errors or warnings in this structure.
2450%
2451*/
2452MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002453 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002454 PixelPacket *pixel,ExceptionInfo *exception)
2455{
2456 GetOneVirtualPixelFromHandler
2457 get_one_virtual_pixel_from_handler;
2458
2459 CacheInfo
2460 *cache_info;
2461
2462 MagickBooleanType
2463 status;
2464
2465 assert(image != (const Image *) NULL);
2466 assert(image->signature == MagickSignature);
2467 assert(image->cache != (Cache) NULL);
2468 cache_info=(CacheInfo *) image->cache;
2469 assert(cache_info->signature == MagickSignature);
2470 *pixel=image->background_color;
2471 get_one_virtual_pixel_from_handler=
2472 cache_info->methods.get_one_virtual_pixel_from_handler;
2473 if (get_one_virtual_pixel_from_handler ==
2474 (GetOneVirtualPixelFromHandler) NULL)
2475 return(MagickFalse);
2476 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2477 pixel,exception);
2478 return(status);
2479}
2480
2481/*
2482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2483% %
2484% %
2485% %
2486% G e t O n e V i r t u a l P i x e l %
2487% %
2488% %
2489% %
2490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2491%
2492% GetOneVirtualPixel() returns a single virtual pixel at the specified
2493% (x,y) location. The image background color is returned if an error occurs.
2494% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2495%
2496% The format of the GetOneVirtualPixel() method is:
2497%
cristybb503372010-05-27 20:51:26 +00002498% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2499% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002500%
2501% A description of each parameter follows:
2502%
2503% o image: the image.
2504%
2505% o x,y: These values define the location of the pixel to return.
2506%
2507% o pixel: return a pixel at the specified (x,y) location.
2508%
2509% o exception: return any errors or warnings in this structure.
2510%
2511*/
2512MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002513 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002514{
2515 GetOneVirtualPixelFromHandler
2516 get_one_virtual_pixel_from_handler;
2517
2518 CacheInfo
2519 *cache_info;
2520
2521 MagickBooleanType
2522 status;
2523
2524 assert(image != (const Image *) NULL);
2525 assert(image->signature == MagickSignature);
2526 assert(image->cache != (Cache) NULL);
2527 cache_info=(CacheInfo *) image->cache;
2528 assert(cache_info->signature == MagickSignature);
2529 *pixel=image->background_color;
2530 get_one_virtual_pixel_from_handler=
2531 cache_info->methods.get_one_virtual_pixel_from_handler;
2532 if (get_one_virtual_pixel_from_handler ==
2533 (GetOneVirtualPixelFromHandler) NULL)
2534 return(MagickFalse);
2535 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2536 image),x,y,pixel,exception);
2537 return(status);
2538}
2539
2540/*
2541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2542% %
2543% %
2544% %
2545+ 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 %
2546% %
2547% %
2548% %
2549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2550%
2551% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2552% specified (x,y) location. The image background color is returned if an
2553% error occurs.
2554%
2555% The format of the GetOneVirtualPixelFromCache() method is:
2556%
2557% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002558% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002559% PixelPacket *pixel,ExceptionInfo *exception)
2560%
2561% A description of each parameter follows:
2562%
2563% o image: the image.
2564%
2565% o virtual_pixel_method: the virtual pixel method.
2566%
2567% o x,y: These values define the location of the pixel to return.
2568%
2569% o pixel: return a pixel at the specified (x,y) location.
2570%
2571% o exception: return any errors or warnings in this structure.
2572%
2573*/
2574static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002575 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002576 PixelPacket *pixel,ExceptionInfo *exception)
2577{
2578 const PixelPacket
2579 *pixels;
2580
2581 *pixel=image->background_color;
2582 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2583 if (pixels == (const PixelPacket *) NULL)
2584 return(MagickFalse);
2585 *pixel=(*pixels);
2586 return(MagickTrue);
2587}
2588
2589/*
2590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591% %
2592% %
2593% %
2594+ G e t P i x e l C a c h e C o l o r s p a c e %
2595% %
2596% %
2597% %
2598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2599%
2600% GetPixelCacheColorspace() returns the class type of the pixel cache.
2601%
2602% The format of the GetPixelCacheColorspace() method is:
2603%
2604% Colorspace GetPixelCacheColorspace(Cache cache)
2605%
2606% A description of each parameter follows:
2607%
2608% o cache: the pixel cache.
2609%
2610*/
2611MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2612{
2613 CacheInfo
2614 *cache_info;
2615
2616 assert(cache != (Cache) NULL);
2617 cache_info=(CacheInfo *) cache;
2618 assert(cache_info->signature == MagickSignature);
2619 if (cache_info->debug != MagickFalse)
2620 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2621 cache_info->filename);
2622 return(cache_info->colorspace);
2623}
2624
2625/*
2626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2627% %
2628% %
2629% %
2630+ G e t P i x e l C a c h e M e t h o d s %
2631% %
2632% %
2633% %
2634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2635%
2636% GetPixelCacheMethods() initializes the CacheMethods structure.
2637%
2638% The format of the GetPixelCacheMethods() method is:
2639%
2640% void GetPixelCacheMethods(CacheMethods *cache_methods)
2641%
2642% A description of each parameter follows:
2643%
2644% o cache_methods: Specifies a pointer to a CacheMethods structure.
2645%
2646*/
2647MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2648{
2649 assert(cache_methods != (CacheMethods *) NULL);
2650 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2651 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2652 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2653 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2654 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2655 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2656 cache_methods->get_authentic_indexes_from_handler=
2657 GetAuthenticIndexesFromCache;
2658 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2659 cache_methods->get_one_authentic_pixel_from_handler=
2660 GetOneAuthenticPixelFromCache;
2661 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2662 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2663 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2664}
2665
2666/*
2667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668% %
2669% %
2670% %
2671+ G e t P i x e l C a c h e N e x u s E x t e n t %
2672% %
2673% %
2674% %
2675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2676%
2677% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2678% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2679%
2680% The format of the GetPixelCacheNexusExtent() method is:
2681%
2682% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2683% NexusInfo *nexus_info)
2684%
2685% A description of each parameter follows:
2686%
2687% o nexus_info: the nexus info.
2688%
2689*/
2690MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2691 NexusInfo *nexus_info)
2692{
2693 CacheInfo
2694 *cache_info;
2695
2696 MagickSizeType
2697 extent;
2698
2699 if (cache == (Cache) NULL)
2700 return(0);
2701 cache_info=(CacheInfo *) cache;
2702 assert(cache_info->signature == MagickSignature);
2703 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2704 if (extent == 0)
2705 return((MagickSizeType) cache_info->columns*cache_info->rows);
2706 return(extent);
2707}
2708
2709/*
2710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711% %
2712% %
2713% %
2714+ 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 %
2715% %
2716% %
2717% %
2718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719%
2720% GetPixelCacheNexusIndexes() returns the indexes associated with the
2721% specified cache nexus.
2722%
2723% The format of the GetPixelCacheNexusIndexes() method is:
2724%
2725% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2726% NexusInfo *nexus_info)
2727%
2728% A description of each parameter follows:
2729%
2730% o cache: the pixel cache.
2731%
2732% o nexus_info: the cache nexus to return the colormap indexes.
2733%
2734*/
2735MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2736 NexusInfo *nexus_info)
2737{
2738 CacheInfo
2739 *cache_info;
2740
2741 if (cache == (Cache) NULL)
2742 return((IndexPacket *) NULL);
2743 cache_info=(CacheInfo *) cache;
2744 assert(cache_info->signature == MagickSignature);
2745 if (cache_info->storage_class == UndefinedClass)
2746 return((IndexPacket *) NULL);
2747 return(nexus_info->indexes);
2748}
2749
2750/*
2751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2752% %
2753% %
2754% %
2755+ G e t P i x e l C a c h e N e x u s P i x e l s %
2756% %
2757% %
2758% %
2759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2760%
2761% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2762% cache nexus.
2763%
2764% The format of the GetPixelCacheNexusPixels() method is:
2765%
2766% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2767% NexusInfo *nexus_info)
2768%
2769% A description of each parameter follows:
2770%
2771% o cache: the pixel cache.
2772%
2773% o nexus_info: the cache nexus to return the pixels.
2774%
2775*/
2776MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2777 NexusInfo *nexus_info)
2778{
2779 CacheInfo
2780 *cache_info;
2781
2782 if (cache == (Cache) NULL)
2783 return((PixelPacket *) NULL);
2784 cache_info=(CacheInfo *) cache;
2785 assert(cache_info->signature == MagickSignature);
2786 if (cache_info->debug != MagickFalse)
2787 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2788 cache_info->filename);
2789 if (cache_info->storage_class == UndefinedClass)
2790 return((PixelPacket *) NULL);
2791 return(nexus_info->pixels);
2792}
2793
2794/*
2795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796% %
2797% %
2798% %
cristy056ba772010-01-02 23:33:54 +00002799+ G e t P i x e l C a c h e P i x e l s %
2800% %
2801% %
2802% %
2803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804%
2805% GetPixelCachePixels() returns the pixels associated with the specified image.
2806%
2807% The format of the GetPixelCachePixels() method is:
2808%
cristyf84a1932010-01-03 18:00:18 +00002809% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2810% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002811%
2812% A description of each parameter follows:
2813%
2814% o image: the image.
2815%
2816% o length: the pixel cache length.
2817%
cristyf84a1932010-01-03 18:00:18 +00002818% o exception: return any errors or warnings in this structure.
2819%
cristy056ba772010-01-02 23:33:54 +00002820*/
cristyf84a1932010-01-03 18:00:18 +00002821MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2822 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002823{
2824 CacheInfo
2825 *cache_info;
2826
2827 assert(image != (const Image *) NULL);
2828 assert(image->signature == MagickSignature);
2829 if (image->debug != MagickFalse)
2830 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2831 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002832 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002833 assert(cache_info->signature == MagickSignature);
2834 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002835 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002836 return((void *) NULL);
2837 *length=cache_info->length;
2838 return((void *) cache_info->pixels);
2839}
2840
2841/*
2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843% %
2844% %
2845% %
cristyb32b90a2009-09-07 21:45:48 +00002846+ 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 +00002847% %
2848% %
2849% %
2850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2851%
2852% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2853%
2854% The format of the GetPixelCacheStorageClass() method is:
2855%
2856% ClassType GetPixelCacheStorageClass(Cache cache)
2857%
2858% A description of each parameter follows:
2859%
2860% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2861%
2862% o cache: the pixel cache.
2863%
2864*/
2865MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2866{
2867 CacheInfo
2868 *cache_info;
2869
2870 assert(cache != (Cache) NULL);
2871 cache_info=(CacheInfo *) cache;
2872 assert(cache_info->signature == MagickSignature);
2873 if (cache_info->debug != MagickFalse)
2874 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2875 cache_info->filename);
2876 return(cache_info->storage_class);
2877}
2878
2879/*
2880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2881% %
2882% %
2883% %
cristyb32b90a2009-09-07 21:45:48 +00002884+ G e t P i x e l C a c h e T i l e S i z e %
2885% %
2886% %
2887% %
2888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2889%
2890% GetPixelCacheTileSize() returns the pixel cache tile size.
2891%
2892% The format of the GetPixelCacheTileSize() method is:
2893%
cristybb503372010-05-27 20:51:26 +00002894% void GetPixelCacheTileSize(const Image *image,size_t *width,
2895% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002896%
2897% A description of each parameter follows:
2898%
2899% o image: the image.
2900%
2901% o width: the optimize cache tile width in pixels.
2902%
2903% o height: the optimize cache tile height in pixels.
2904%
2905*/
cristybb503372010-05-27 20:51:26 +00002906MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2907 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002908{
2909 CacheInfo
2910 *cache_info;
2911
2912 assert(image != (Image *) NULL);
2913 assert(image->signature == MagickSignature);
2914 if (image->debug != MagickFalse)
2915 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2916 assert(image->cache != (Cache) NULL);
2917 cache_info=(CacheInfo *) image->cache;
2918 assert(cache_info->signature == MagickSignature);
2919 *width=2048UL/sizeof(PixelPacket);
2920 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002921 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002922 *height=(*width);
2923}
2924
2925/*
2926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927% %
2928% %
2929% %
2930+ G e t P i x e l C a c h e T y p e %
2931% %
2932% %
2933% %
2934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2935%
2936% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2937%
2938% The format of the GetPixelCacheType() method is:
2939%
2940% CacheType GetPixelCacheType(const Image *image)
2941%
2942% A description of each parameter follows:
2943%
2944% o image: the image.
2945%
2946*/
2947MagickExport CacheType GetPixelCacheType(const Image *image)
2948{
2949 CacheInfo
2950 *cache_info;
2951
2952 assert(image != (Image *) NULL);
2953 assert(image->signature == MagickSignature);
2954 if (image->debug != MagickFalse)
2955 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2956 assert(image->cache != (Cache) NULL);
2957 cache_info=(CacheInfo *) image->cache;
2958 assert(cache_info->signature == MagickSignature);
2959 return(cache_info->type);
2960}
2961
2962/*
2963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2964% %
2965% %
2966% %
cristy3ed852e2009-09-05 21:47:34 +00002967+ 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 %
2968% %
2969% %
2970% %
2971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2972%
2973% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2974% pixel cache. A virtual pixel is any pixel access that is outside the
2975% boundaries of the image cache.
2976%
2977% The format of the GetPixelCacheVirtualMethod() method is:
2978%
2979% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2980%
2981% A description of each parameter follows:
2982%
2983% o image: the image.
2984%
2985*/
2986MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2987{
2988 CacheInfo
2989 *cache_info;
2990
2991 assert(image != (Image *) NULL);
2992 assert(image->signature == MagickSignature);
2993 if (image->debug != MagickFalse)
2994 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2995 assert(image->cache != (Cache) NULL);
2996 cache_info=(CacheInfo *) image->cache;
2997 assert(cache_info->signature == MagickSignature);
2998 return(cache_info->virtual_pixel_method);
2999}
3000
3001/*
3002%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3003% %
3004% %
3005% %
3006+ G e t V i r t u a l I n d e x e s F r o m C a c h e %
3007% %
3008% %
3009% %
3010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3011%
3012% GetVirtualIndexesFromCache() returns the indexes associated with the last
3013% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3014%
3015% The format of the GetVirtualIndexesFromCache() method is:
3016%
3017% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3018%
3019% A description of each parameter follows:
3020%
3021% o image: the image.
3022%
3023*/
3024static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3025{
3026 CacheInfo
3027 *cache_info;
3028
3029 const IndexPacket
3030 *indexes;
3031
cristybb503372010-05-27 20:51:26 +00003032 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003033 id;
3034
3035 if (image->debug != MagickFalse)
3036 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3037 cache_info=(CacheInfo *) image->cache;
3038 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003039 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003040 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3041 return(indexes);
3042}
3043
3044/*
3045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046% %
3047% %
3048% %
3049+ 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 %
3050% %
3051% %
3052% %
3053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3054%
3055% GetVirtualIndexesFromNexus() returns the indexes associated with the
3056% specified cache nexus.
3057%
3058% The format of the GetVirtualIndexesFromNexus() method is:
3059%
3060% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3061% NexusInfo *nexus_info)
3062%
3063% A description of each parameter follows:
3064%
3065% o cache: the pixel cache.
3066%
3067% o nexus_info: the cache nexus to return the colormap indexes.
3068%
3069*/
3070MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3071 NexusInfo *nexus_info)
3072{
3073 CacheInfo
3074 *cache_info;
3075
3076 if (cache == (Cache) NULL)
3077 return((IndexPacket *) NULL);
3078 cache_info=(CacheInfo *) cache;
3079 assert(cache_info->signature == MagickSignature);
3080 if (cache_info->storage_class == UndefinedClass)
3081 return((IndexPacket *) NULL);
3082 return(nexus_info->indexes);
3083}
3084
3085/*
3086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3087% %
3088% %
3089% %
3090% G e t V i r t u a l I n d e x Q u e u e %
3091% %
3092% %
3093% %
3094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3095%
3096% GetVirtualIndexQueue() returns the virtual black channel or the
3097% colormap indexes associated with the last call to QueueAuthenticPixels() or
3098% GetVirtualPixels(). NULL is returned if the black channel or colormap
3099% indexes are not available.
3100%
3101% The format of the GetVirtualIndexQueue() method is:
3102%
3103% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3104%
3105% A description of each parameter follows:
3106%
3107% o image: the image.
3108%
3109*/
3110MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3111{
3112 CacheInfo
3113 *cache_info;
3114
3115 assert(image != (const Image *) NULL);
3116 assert(image->signature == MagickSignature);
3117 if (image->debug != MagickFalse)
3118 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3119 assert(image->cache != (Cache) NULL);
3120 cache_info=(CacheInfo *) image->cache;
3121 assert(cache_info->signature == MagickSignature);
3122 if (cache_info->methods.get_virtual_indexes_from_handler ==
3123 (GetVirtualIndexesFromHandler) NULL)
3124 return((IndexPacket *) NULL);
3125 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3126}
3127
3128/*
3129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3130% %
3131% %
3132% %
3133+ 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 %
3134% %
3135% %
3136% %
3137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3138%
3139% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3140% pixel cache as defined by the geometry parameters. A pointer to the pixels
3141% is returned if the pixels are transferred, otherwise a NULL is returned.
3142%
3143% The format of the GetVirtualPixelsFromNexus() method is:
3144%
3145% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003146% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003147% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3148% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003149%
3150% A description of each parameter follows:
3151%
3152% o image: the image.
3153%
3154% o virtual_pixel_method: the virtual pixel method.
3155%
3156% o x,y,columns,rows: These values define the perimeter of a region of
3157% pixels.
3158%
3159% o nexus_info: the cache nexus to acquire.
3160%
3161% o exception: return any errors or warnings in this structure.
3162%
3163*/
3164
cristybb503372010-05-27 20:51:26 +00003165static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003166 DitherMatrix[64] =
3167 {
3168 0, 48, 12, 60, 3, 51, 15, 63,
3169 32, 16, 44, 28, 35, 19, 47, 31,
3170 8, 56, 4, 52, 11, 59, 7, 55,
3171 40, 24, 36, 20, 43, 27, 39, 23,
3172 2, 50, 14, 62, 1, 49, 13, 61,
3173 34, 18, 46, 30, 33, 17, 45, 29,
3174 10, 58, 6, 54, 9, 57, 5, 53,
3175 42, 26, 38, 22, 41, 25, 37, 21
3176 };
3177
cristybb503372010-05-27 20:51:26 +00003178static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003179{
cristybb503372010-05-27 20:51:26 +00003180 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003181 index;
3182
3183 index=x+DitherMatrix[x & 0x07]-32L;
3184 if (index < 0L)
3185 return(0L);
cristybb503372010-05-27 20:51:26 +00003186 if (index >= (ssize_t) columns)
3187 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003188 return(index);
3189}
3190
cristybb503372010-05-27 20:51:26 +00003191static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003192{
cristybb503372010-05-27 20:51:26 +00003193 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003194 index;
3195
3196 index=y+DitherMatrix[y & 0x07]-32L;
3197 if (index < 0L)
3198 return(0L);
cristybb503372010-05-27 20:51:26 +00003199 if (index >= (ssize_t) rows)
3200 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003201 return(index);
3202}
3203
cristybb503372010-05-27 20:51:26 +00003204static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003205{
3206 if (x < 0L)
3207 return(0L);
cristybb503372010-05-27 20:51:26 +00003208 if (x >= (ssize_t) columns)
3209 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003210 return(x);
3211}
3212
cristybb503372010-05-27 20:51:26 +00003213static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003214{
3215 if (y < 0L)
3216 return(0L);
cristybb503372010-05-27 20:51:26 +00003217 if (y >= (ssize_t) rows)
3218 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003219 return(y);
3220}
3221
cristybb503372010-05-27 20:51:26 +00003222static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003223{
cristybb503372010-05-27 20:51:26 +00003224 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003225}
3226
cristybb503372010-05-27 20:51:26 +00003227static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003228{
cristybb503372010-05-27 20:51:26 +00003229 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003230}
3231
3232/*
3233 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3234 returns not only the quotient (tile the offset falls in) but also the positive
3235 remainer within that tile such that 0 <= remainder < extent. This method is
3236 essentially a ldiv() using a floored modulo division rather than the normal
3237 default truncated modulo division.
3238*/
cristybb503372010-05-27 20:51:26 +00003239static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3240 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003241{
3242 MagickModulo
3243 modulo;
3244
cristybb503372010-05-27 20:51:26 +00003245 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003246 if (offset < 0L)
3247 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003248 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003249 return(modulo);
3250}
3251
3252MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003253 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3254 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003255 ExceptionInfo *exception)
3256{
3257 CacheInfo
3258 *cache_info;
3259
cristyc3ec0d42010-04-07 01:18:08 +00003260 IndexPacket
3261 virtual_index;
3262
cristy3ed852e2009-09-05 21:47:34 +00003263 MagickOffsetType
3264 offset;
3265
3266 MagickSizeType
3267 length,
3268 number_pixels;
3269
3270 NexusInfo
3271 **virtual_nexus;
3272
3273 PixelPacket
3274 *pixels,
3275 virtual_pixel;
3276
3277 RectangleInfo
3278 region;
3279
3280 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003281 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003282
3283 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003284 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003285
3286 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003287 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003288
cristybb503372010-05-27 20:51:26 +00003289 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003290 u,
3291 v;
3292
3293 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003294 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003295
3296 /*
3297 Acquire pixels.
3298 */
3299 if (image->debug != MagickFalse)
3300 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3301 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003302 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003303 return((const PixelPacket *) NULL);
3304 region.x=x;
3305 region.y=y;
3306 region.width=columns;
3307 region.height=rows;
3308 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3309 if (pixels == (PixelPacket *) NULL)
3310 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003311 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3312 nexus_info->region.x;
3313 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3314 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003315 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3316 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003317 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3318 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003319 {
3320 MagickBooleanType
3321 status;
3322
3323 /*
3324 Pixel request is inside cache extents.
3325 */
3326 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3327 return(pixels);
3328 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3329 if (status == MagickFalse)
3330 return((const PixelPacket *) NULL);
3331 if ((cache_info->storage_class == PseudoClass) ||
3332 (cache_info->colorspace == CMYKColorspace))
3333 {
3334 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3335 if (status == MagickFalse)
3336 return((const PixelPacket *) NULL);
3337 }
3338 return(pixels);
3339 }
3340 /*
3341 Pixel request is outside cache extents.
3342 */
3343 q=pixels;
3344 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3345 virtual_nexus=AcquirePixelCacheNexus(1);
3346 if (virtual_nexus == (NexusInfo **) NULL)
3347 {
3348 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3349 "UnableToGetCacheNexus","`%s'",image->filename);
3350 return((const PixelPacket *) NULL);
3351 }
3352 switch (virtual_pixel_method)
3353 {
3354 case BlackVirtualPixelMethod:
3355 {
cristy4789f0d2010-01-10 00:01:06 +00003356 SetRedPixelComponent(&virtual_pixel,0);
3357 SetGreenPixelComponent(&virtual_pixel,0);
3358 SetBluePixelComponent(&virtual_pixel,0);
3359 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003360 break;
3361 }
3362 case GrayVirtualPixelMethod:
3363 {
cristy4789f0d2010-01-10 00:01:06 +00003364 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3365 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3366 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3367 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003368 break;
3369 }
3370 case TransparentVirtualPixelMethod:
3371 {
cristy4789f0d2010-01-10 00:01:06 +00003372 SetRedPixelComponent(&virtual_pixel,0);
3373 SetGreenPixelComponent(&virtual_pixel,0);
3374 SetBluePixelComponent(&virtual_pixel,0);
3375 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003376 break;
3377 }
3378 case MaskVirtualPixelMethod:
3379 case WhiteVirtualPixelMethod:
3380 {
cristy4789f0d2010-01-10 00:01:06 +00003381 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3382 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3383 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3384 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003385 break;
3386 }
3387 default:
3388 {
3389 virtual_pixel=image->background_color;
3390 break;
3391 }
3392 }
cristyc3ec0d42010-04-07 01:18:08 +00003393 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003394 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003395 {
cristybb503372010-05-27 20:51:26 +00003396 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003397 {
3398 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003399 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003400 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3401 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003402 {
3403 MagickModulo
3404 x_modulo,
3405 y_modulo;
3406
3407 /*
3408 Transfer a single pixel.
3409 */
3410 length=(MagickSizeType) 1;
3411 switch (virtual_pixel_method)
3412 {
3413 case BackgroundVirtualPixelMethod:
3414 case ConstantVirtualPixelMethod:
3415 case BlackVirtualPixelMethod:
3416 case GrayVirtualPixelMethod:
3417 case TransparentVirtualPixelMethod:
3418 case MaskVirtualPixelMethod:
3419 case WhiteVirtualPixelMethod:
3420 {
3421 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003422 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003423 break;
3424 }
3425 case EdgeVirtualPixelMethod:
3426 default:
3427 {
3428 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003429 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003430 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003431 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3432 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003433 break;
3434 }
3435 case RandomVirtualPixelMethod:
3436 {
3437 if (cache_info->random_info == (RandomInfo *) NULL)
3438 cache_info->random_info=AcquireRandomInfo();
3439 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003440 RandomX(cache_info->random_info,cache_info->columns),
3441 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003442 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003443 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3444 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003445 break;
3446 }
3447 case DitherVirtualPixelMethod:
3448 {
3449 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003450 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003451 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003452 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3453 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003454 break;
3455 }
3456 case TileVirtualPixelMethod:
3457 {
3458 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3459 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3460 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3461 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3462 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003463 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3464 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003465 break;
3466 }
3467 case MirrorVirtualPixelMethod:
3468 {
3469 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3470 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003471 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003472 x_modulo.remainder-1L;
3473 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3474 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003475 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003476 y_modulo.remainder-1L;
3477 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3478 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3479 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003480 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3481 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003482 break;
3483 }
3484 case CheckerTileVirtualPixelMethod:
3485 {
3486 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3487 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3488 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3489 {
3490 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003491 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003492 break;
3493 }
3494 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3495 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3496 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003497 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3498 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003499 break;
3500 }
3501 case HorizontalTileVirtualPixelMethod:
3502 {
cristybb503372010-05-27 20:51:26 +00003503 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003504 {
3505 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003506 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003507 break;
3508 }
3509 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3510 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3511 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3512 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3513 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003514 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3515 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003516 break;
3517 }
3518 case VerticalTileVirtualPixelMethod:
3519 {
cristybb503372010-05-27 20:51:26 +00003520 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003521 {
3522 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003523 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003524 break;
3525 }
3526 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3527 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3528 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3529 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3530 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003531 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3532 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003533 break;
3534 }
3535 case HorizontalTileEdgeVirtualPixelMethod:
3536 {
3537 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3538 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003539 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003540 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003541 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3542 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003543 break;
3544 }
3545 case VerticalTileEdgeVirtualPixelMethod:
3546 {
3547 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3548 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003549 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003550 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003551 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3552 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003553 break;
3554 }
3555 }
3556 if (p == (const PixelPacket *) NULL)
3557 break;
3558 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003559 if ((indexes != (IndexPacket *) NULL) &&
3560 (virtual_indexes != (const IndexPacket *) NULL))
3561 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003562 continue;
3563 }
3564 /*
3565 Transfer a run of pixels.
3566 */
3567 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003568 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003569 if (p == (const PixelPacket *) NULL)
3570 break;
cristyc3ec0d42010-04-07 01:18:08 +00003571 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003572 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3573 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003574 if ((indexes != (IndexPacket *) NULL) &&
3575 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003576 {
cristyc3ec0d42010-04-07 01:18:08 +00003577 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3578 sizeof(*virtual_indexes));
3579 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003580 }
3581 }
3582 }
3583 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3584 return(pixels);
3585}
3586
3587/*
3588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3589% %
3590% %
3591% %
3592+ G e t V i r t u a l P i x e l C a c h e %
3593% %
3594% %
3595% %
3596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3597%
3598% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3599% cache as defined by the geometry parameters. A pointer to the pixels
3600% is returned if the pixels are transferred, otherwise a NULL is returned.
3601%
3602% The format of the GetVirtualPixelCache() method is:
3603%
3604% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003605% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3606% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003607% ExceptionInfo *exception)
3608%
3609% A description of each parameter follows:
3610%
3611% o image: the image.
3612%
3613% o virtual_pixel_method: the virtual pixel method.
3614%
3615% o x,y,columns,rows: These values define the perimeter of a region of
3616% pixels.
3617%
3618% o exception: return any errors or warnings in this structure.
3619%
3620*/
3621static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003622 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3623 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003624{
3625 CacheInfo
3626 *cache_info;
3627
3628 const PixelPacket
3629 *pixels;
3630
cristybb503372010-05-27 20:51:26 +00003631 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003632 id;
3633
3634 if (image->debug != MagickFalse)
3635 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3636 cache_info=(CacheInfo *) image->cache;
3637 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003638 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003639 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3640 cache_info->nexus_info[id],exception);
3641 return(pixels);
3642}
3643
3644/*
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646% %
3647% %
3648% %
3649% G e t V i r t u a l P i x e l Q u e u e %
3650% %
3651% %
3652% %
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654%
3655% GetVirtualPixelQueue() returns the virtual pixels associated with the
3656% last call to QueueAuthenticPixels() or GetVirtualPixels().
3657%
3658% The format of the GetVirtualPixelQueue() method is:
3659%
3660% const PixelPacket *GetVirtualPixelQueue(const Image image)
3661%
3662% A description of each parameter follows:
3663%
3664% o image: the image.
3665%
3666*/
3667MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3668{
3669 CacheInfo
3670 *cache_info;
3671
3672 assert(image != (const Image *) NULL);
3673 assert(image->signature == MagickSignature);
3674 if (image->debug != MagickFalse)
3675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3676 assert(image->cache != (Cache) NULL);
3677 cache_info=(CacheInfo *) image->cache;
3678 assert(cache_info->signature == MagickSignature);
3679 if (cache_info->methods.get_virtual_pixels_handler ==
3680 (GetVirtualPixelsHandler) NULL)
3681 return((PixelPacket *) NULL);
3682 return(cache_info->methods.get_virtual_pixels_handler(image));
3683}
3684
3685/*
3686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3687% %
3688% %
3689% %
3690% G e t V i r t u a l P i x e l s %
3691% %
3692% %
3693% %
3694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3695%
3696% GetVirtualPixels() returns an immutable pixel region. If the
3697% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003698% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003699% copy of the pixels or it may point to the original pixels in memory.
3700% Performance is maximized if the selected region is part of one row, or one
3701% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003702% (without a copy) if the image is in memory, or in a memory-mapped file. The
3703% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003704%
3705% Pixels accessed via the returned pointer represent a simple array of type
3706% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3707% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3708% the black color component or to obtain the colormap indexes (of type
3709% IndexPacket) corresponding to the region.
3710%
3711% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3712%
3713% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3714% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3715% GetCacheViewAuthenticPixels() instead.
3716%
3717% The format of the GetVirtualPixels() method is:
3718%
cristybb503372010-05-27 20:51:26 +00003719% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3720% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003721% ExceptionInfo *exception)
3722%
3723% A description of each parameter follows:
3724%
3725% o image: the image.
3726%
3727% o x,y,columns,rows: These values define the perimeter of a region of
3728% pixels.
3729%
3730% o exception: return any errors or warnings in this structure.
3731%
3732*/
3733MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003734 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3735 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003736{
3737 CacheInfo
3738 *cache_info;
3739
3740 const PixelPacket
3741 *pixels;
3742
3743 assert(image != (const Image *) NULL);
3744 assert(image->signature == MagickSignature);
3745 if (image->debug != MagickFalse)
3746 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3747 assert(image->cache != (Cache) NULL);
3748 cache_info=(CacheInfo *) image->cache;
3749 assert(cache_info->signature == MagickSignature);
3750 if (cache_info->methods.get_virtual_pixel_handler ==
3751 (GetVirtualPixelHandler) NULL)
3752 return((const PixelPacket *) NULL);
3753 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3754 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3755 return(pixels);
3756}
3757
3758/*
3759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3760% %
3761% %
3762% %
3763+ 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 %
3764% %
3765% %
3766% %
3767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3768%
3769% GetVirtualPixelsCache() returns the pixels associated with the last call
3770% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3771%
3772% The format of the GetVirtualPixelsCache() method is:
3773%
3774% PixelPacket *GetVirtualPixelsCache(const Image *image)
3775%
3776% A description of each parameter follows:
3777%
3778% o image: the image.
3779%
3780*/
3781static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3782{
3783 CacheInfo
3784 *cache_info;
3785
3786 const PixelPacket
3787 *pixels;
3788
cristybb503372010-05-27 20:51:26 +00003789 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003790 id;
3791
3792 if (image->debug != MagickFalse)
3793 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3794 cache_info=(CacheInfo *) image->cache;
3795 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003796 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003797 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3798 return(pixels);
3799}
3800
3801/*
3802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3803% %
3804% %
3805% %
3806+ G e t V i r t u a l P i x e l s N e x u s %
3807% %
3808% %
3809% %
3810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3811%
3812% GetVirtualPixelsNexus() returns the pixels associated with the specified
3813% cache nexus.
3814%
3815% The format of the GetVirtualPixelsNexus() method is:
3816%
3817% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3818% NexusInfo *nexus_info)
3819%
3820% A description of each parameter follows:
3821%
3822% o cache: the pixel cache.
3823%
3824% o nexus_info: the cache nexus to return the colormap pixels.
3825%
3826*/
3827MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3828 NexusInfo *nexus_info)
3829{
3830 CacheInfo
3831 *cache_info;
3832
3833 if (cache == (Cache) NULL)
3834 return((PixelPacket *) NULL);
3835 cache_info=(CacheInfo *) cache;
3836 assert(cache_info->signature == MagickSignature);
3837 if (cache_info->storage_class == UndefinedClass)
3838 return((PixelPacket *) NULL);
3839 return((const PixelPacket *) nexus_info->pixels);
3840}
3841
3842/*
3843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3844% %
3845% %
3846% %
3847+ M a s k P i x e l C a c h e N e x u s %
3848% %
3849% %
3850% %
3851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3852%
3853% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3854% The method returns MagickTrue if the pixel region is masked, otherwise
3855% MagickFalse.
3856%
3857% The format of the MaskPixelCacheNexus() method is:
3858%
3859% MagickBooleanType MaskPixelCacheNexus(Image *image,
3860% NexusInfo *nexus_info,ExceptionInfo *exception)
3861%
3862% A description of each parameter follows:
3863%
3864% o image: the image.
3865%
3866% o nexus_info: the cache nexus to clip.
3867%
3868% o exception: return any errors or warnings in this structure.
3869%
3870*/
3871
3872static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3873 const MagickRealType alpha,const MagickPixelPacket *q,
3874 const MagickRealType beta,MagickPixelPacket *composite)
3875{
3876 MagickRealType
3877 gamma;
3878
3879 if (alpha == TransparentOpacity)
3880 {
3881 *composite=(*q);
3882 return;
3883 }
3884 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3885 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3886 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3887 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3888 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3889 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3890 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3891}
3892
3893static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3894 ExceptionInfo *exception)
3895{
3896 CacheInfo
3897 *cache_info;
3898
3899 MagickPixelPacket
3900 alpha,
3901 beta;
3902
3903 MagickSizeType
3904 number_pixels;
3905
3906 NexusInfo
3907 **clip_nexus,
3908 **image_nexus;
3909
3910 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003911 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003912
3913 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003914 *restrict nexus_indexes,
3915 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003916
cristybb503372010-05-27 20:51:26 +00003917 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003918 i;
3919
3920 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003921 *restrict p,
3922 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003923
3924 /*
3925 Apply clip mask.
3926 */
3927 if (image->debug != MagickFalse)
3928 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3929 if (image->mask == (Image *) NULL)
3930 return(MagickFalse);
3931 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3932 if (cache_info == (Cache) NULL)
3933 return(MagickFalse);
3934 image_nexus=AcquirePixelCacheNexus(1);
3935 clip_nexus=AcquirePixelCacheNexus(1);
3936 if ((image_nexus == (NexusInfo **) NULL) ||
3937 (clip_nexus == (NexusInfo **) NULL))
3938 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003939 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3940 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3941 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003942 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3943 q=nexus_info->pixels;
3944 nexus_indexes=nexus_info->indexes;
3945 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3946 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3947 nexus_info->region.height,clip_nexus[0],&image->exception);
3948 GetMagickPixelPacket(image,&alpha);
3949 GetMagickPixelPacket(image,&beta);
3950 number_pixels=(MagickSizeType) nexus_info->region.width*
3951 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003952 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003953 {
3954 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3955 break;
3956 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3957 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3958 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3959 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003960 q->red=ClampToQuantum(beta.red);
3961 q->green=ClampToQuantum(beta.green);
3962 q->blue=ClampToQuantum(beta.blue);
3963 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003964 if (cache_info->active_index_channel != MagickFalse)
3965 nexus_indexes[i]=indexes[i];
3966 p++;
3967 q++;
3968 r++;
3969 }
3970 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3971 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003972 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003973 return(MagickFalse);
3974 return(MagickTrue);
3975}
3976
3977/*
3978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3979% %
3980% %
3981% %
3982+ O p e n P i x e l C a c h e %
3983% %
3984% %
3985% %
3986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3987%
3988% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3989% dimensions, allocating space for the image pixels and optionally the
3990% colormap indexes, and memory mapping the cache if it is disk based. The
3991% cache nexus array is initialized as well.
3992%
3993% The format of the OpenPixelCache() method is:
3994%
3995% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3996% ExceptionInfo *exception)
3997%
3998% A description of each parameter follows:
3999%
4000% o image: the image.
4001%
4002% o mode: ReadMode, WriteMode, or IOMode.
4003%
4004% o exception: return any errors or warnings in this structure.
4005%
4006*/
4007
cristyd43a46b2010-01-21 02:13:41 +00004008static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00004009{
4010 cache_info->mapped=MagickFalse;
4011 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
4012 cache_info->length);
4013 if (cache_info->pixels == (PixelPacket *) NULL)
4014 {
4015 cache_info->mapped=MagickTrue;
4016 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4017 cache_info->length);
4018 }
4019}
4020
4021static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4022{
4023 CacheInfo
4024 *cache_info;
4025
4026 MagickOffsetType
4027 count,
4028 extent,
4029 offset;
4030
4031 cache_info=(CacheInfo *) image->cache;
4032 if (image->debug != MagickFalse)
4033 {
4034 char
4035 format[MaxTextExtent],
4036 message[MaxTextExtent];
4037
cristyb9080c92009-12-01 20:13:26 +00004038 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004039 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004040 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004041 cache_info->cache_filename,cache_info->file,format);
4042 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4043 }
4044 if (length != (MagickSizeType) ((MagickOffsetType) length))
4045 return(MagickFalse);
4046 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4047 if (extent < 0)
4048 return(MagickFalse);
4049 if ((MagickSizeType) extent >= length)
4050 return(MagickTrue);
4051 offset=(MagickOffsetType) length-1;
4052 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4053 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4054}
4055
4056static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4057 ExceptionInfo *exception)
4058{
4059 char
4060 format[MaxTextExtent],
4061 message[MaxTextExtent];
4062
4063 CacheInfo
4064 *cache_info,
4065 source_info;
4066
4067 MagickSizeType
4068 length,
4069 number_pixels;
4070
4071 MagickStatusType
4072 status;
4073
4074 size_t
4075 packet_size;
4076
cristybb503372010-05-27 20:51:26 +00004077 size_t
cristy3ed852e2009-09-05 21:47:34 +00004078 columns;
4079
4080 if (image->debug != MagickFalse)
4081 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4082 if ((image->columns == 0) || (image->rows == 0))
4083 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4084 cache_info=(CacheInfo *) image->cache;
4085 source_info=(*cache_info);
4086 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004087 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4088 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004089 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004090 cache_info->rows=image->rows;
4091 cache_info->columns=image->columns;
4092 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4093 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004094 if (image->ping != MagickFalse)
4095 {
4096 cache_info->storage_class=image->storage_class;
4097 cache_info->colorspace=image->colorspace;
4098 cache_info->type=PingCache;
4099 cache_info->pixels=(PixelPacket *) NULL;
4100 cache_info->indexes=(IndexPacket *) NULL;
4101 cache_info->length=0;
4102 return(MagickTrue);
4103 }
cristy3ed852e2009-09-05 21:47:34 +00004104 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4105 packet_size=sizeof(PixelPacket);
4106 if (cache_info->active_index_channel != MagickFalse)
4107 packet_size+=sizeof(IndexPacket);
4108 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004109 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004110 if (cache_info->columns != columns)
4111 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4112 image->filename);
4113 cache_info->length=length;
4114 status=AcquireMagickResource(AreaResource,cache_info->length);
4115 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4116 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4117 {
4118 status=AcquireMagickResource(MemoryResource,cache_info->length);
4119 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4120 (cache_info->type == MemoryCache))
4121 {
cristyd43a46b2010-01-21 02:13:41 +00004122 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004123 if (cache_info->pixels == (PixelPacket *) NULL)
4124 cache_info->pixels=source_info.pixels;
4125 else
4126 {
4127 /*
4128 Create memory pixel cache.
4129 */
4130 if (image->debug != MagickFalse)
4131 {
cristy97e7a572009-12-05 15:07:53 +00004132 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004133 format);
cristy3ed852e2009-09-05 21:47:34 +00004134 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004135 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004136 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004137 (double) cache_info->columns,(double) cache_info->rows,
4138 format);
cristy3ed852e2009-09-05 21:47:34 +00004139 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4140 message);
4141 }
4142 cache_info->storage_class=image->storage_class;
4143 cache_info->colorspace=image->colorspace;
4144 cache_info->type=MemoryCache;
4145 cache_info->indexes=(IndexPacket *) NULL;
4146 if (cache_info->active_index_channel != MagickFalse)
4147 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4148 number_pixels);
4149 if (source_info.storage_class != UndefinedClass)
4150 {
4151 status|=ClonePixelCachePixels(cache_info,&source_info,
4152 exception);
4153 RelinquishPixelCachePixels(&source_info);
4154 }
4155 return(MagickTrue);
4156 }
4157 }
4158 RelinquishMagickResource(MemoryResource,cache_info->length);
4159 }
4160 /*
4161 Create pixel cache on disk.
4162 */
4163 status=AcquireMagickResource(DiskResource,cache_info->length);
4164 if (status == MagickFalse)
4165 {
4166 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4167 "CacheResourcesExhausted","`%s'",image->filename);
4168 return(MagickFalse);
4169 }
4170 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4171 {
4172 RelinquishMagickResource(DiskResource,cache_info->length);
4173 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4174 image->filename);
4175 return(MagickFalse);
4176 }
4177 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4178 cache_info->length);
4179 if (status == MagickFalse)
4180 {
4181 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4182 image->filename);
4183 return(MagickFalse);
4184 }
4185 cache_info->storage_class=image->storage_class;
4186 cache_info->colorspace=image->colorspace;
4187 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4188 status=AcquireMagickResource(AreaResource,cache_info->length);
4189 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4190 cache_info->type=DiskCache;
4191 else
4192 {
4193 status=AcquireMagickResource(MapResource,cache_info->length);
4194 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4195 (cache_info->type != MemoryCache))
4196 cache_info->type=DiskCache;
4197 else
4198 {
4199 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4200 cache_info->offset,(size_t) cache_info->length);
4201 if (cache_info->pixels == (PixelPacket *) NULL)
4202 {
4203 cache_info->pixels=source_info.pixels;
4204 cache_info->type=DiskCache;
4205 }
4206 else
4207 {
4208 /*
4209 Create file-backed memory-mapped pixel cache.
4210 */
4211 (void) ClosePixelCacheOnDisk(cache_info);
4212 cache_info->type=MapCache;
4213 cache_info->mapped=MagickTrue;
4214 cache_info->indexes=(IndexPacket *) NULL;
4215 if (cache_info->active_index_channel != MagickFalse)
4216 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4217 number_pixels);
4218 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4219 {
4220 status=ClonePixelCachePixels(cache_info,&source_info,
4221 exception);
4222 RelinquishPixelCachePixels(&source_info);
4223 }
4224 if (image->debug != MagickFalse)
4225 {
cristy97e7a572009-12-05 15:07:53 +00004226 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004227 format);
cristy3ed852e2009-09-05 21:47:34 +00004228 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004229 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004230 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004231 cache_info->file,(double) cache_info->columns,(double)
4232 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004233 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4234 message);
4235 }
4236 return(MagickTrue);
4237 }
4238 }
4239 RelinquishMagickResource(MapResource,cache_info->length);
4240 }
4241 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4242 {
4243 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4244 RelinquishPixelCachePixels(&source_info);
4245 }
4246 if (image->debug != MagickFalse)
4247 {
cristyb9080c92009-12-01 20:13:26 +00004248 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004249 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004250 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4251 cache_info->cache_filename,cache_info->file,(double)
4252 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004253 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4254 }
4255 return(MagickTrue);
4256}
4257
4258/*
4259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4260% %
4261% %
4262% %
4263+ P e r s i s t P i x e l C a c h e %
4264% %
4265% %
4266% %
4267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4268%
4269% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4270% persistent pixel cache is one that resides on disk and is not destroyed
4271% when the program exits.
4272%
4273% The format of the PersistPixelCache() method is:
4274%
4275% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4276% const MagickBooleanType attach,MagickOffsetType *offset,
4277% ExceptionInfo *exception)
4278%
4279% A description of each parameter follows:
4280%
4281% o image: the image.
4282%
4283% o filename: the persistent pixel cache filename.
4284%
cristy01b7eb02009-09-10 23:10:14 +00004285% o attach: A value other than zero initializes the persistent pixel
4286% cache.
4287%
cristy3ed852e2009-09-05 21:47:34 +00004288% o initialize: A value other than zero initializes the persistent pixel
4289% cache.
4290%
4291% o offset: the offset in the persistent cache to store pixels.
4292%
4293% o exception: return any errors or warnings in this structure.
4294%
4295*/
4296MagickExport MagickBooleanType PersistPixelCache(Image *image,
4297 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4298 ExceptionInfo *exception)
4299{
4300 CacheInfo
4301 *cache_info,
4302 *clone_info;
4303
4304 Image
4305 clone_image;
4306
cristybb503372010-05-27 20:51:26 +00004307 ssize_t
cristy688f07b2009-09-27 15:19:13 +00004308 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004309
4310 MagickBooleanType
4311 status;
4312
4313 assert(image != (Image *) NULL);
4314 assert(image->signature == MagickSignature);
4315 if (image->debug != MagickFalse)
4316 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4317 assert(image->cache != (void *) NULL);
4318 assert(filename != (const char *) NULL);
4319 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004320 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004321 cache_info=(CacheInfo *) image->cache;
4322 assert(cache_info->signature == MagickSignature);
4323 if (attach != MagickFalse)
4324 {
4325 /*
cristy01b7eb02009-09-10 23:10:14 +00004326 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004327 */
4328 if (image->debug != MagickFalse)
4329 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4330 "attach persistent cache");
4331 (void) CopyMagickString(cache_info->cache_filename,filename,
4332 MaxTextExtent);
4333 cache_info->type=DiskCache;
4334 cache_info->offset=(*offset);
4335 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4336 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004337 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004338 return(MagickTrue);
4339 }
cristy01b7eb02009-09-10 23:10:14 +00004340 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4341 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004342 {
cristyf84a1932010-01-03 18:00:18 +00004343 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004344 if ((cache_info->mode != ReadMode) &&
4345 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004346 (cache_info->reference_count == 1))
4347 {
4348 int
4349 status;
4350
4351 /*
cristy01b7eb02009-09-10 23:10:14 +00004352 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004353 */
4354 status=rename(cache_info->cache_filename,filename);
4355 if (status == 0)
4356 {
4357 (void) CopyMagickString(cache_info->cache_filename,filename,
4358 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004359 *offset+=cache_info->length+page_size-(cache_info->length %
4360 page_size);
cristyf84a1932010-01-03 18:00:18 +00004361 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004362 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004363 if (image->debug != MagickFalse)
4364 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4365 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004366 return(MagickTrue);
4367 }
4368 }
cristyf84a1932010-01-03 18:00:18 +00004369 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004370 }
4371 /*
cristy01b7eb02009-09-10 23:10:14 +00004372 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004373 */
4374 clone_image=(*image);
4375 clone_info=(CacheInfo *) clone_image.cache;
4376 image->cache=ClonePixelCache(cache_info);
4377 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4378 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4379 cache_info->type=DiskCache;
4380 cache_info->offset=(*offset);
4381 cache_info=(CacheInfo *) image->cache;
4382 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4383 if (status != MagickFalse)
4384 {
4385 status=OpenPixelCache(image,IOMode,exception);
4386 if (status != MagickFalse)
4387 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4388 }
cristy688f07b2009-09-27 15:19:13 +00004389 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004390 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4391 return(status);
4392}
4393
4394/*
4395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4396% %
4397% %
4398% %
4399+ Q u e u e A u t h e n t i c N e x u s %
4400% %
4401% %
4402% %
4403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4404%
4405% QueueAuthenticNexus() allocates an region to store image pixels as defined
4406% by the region rectangle and returns a pointer to the region. This region is
4407% subsequently transferred from the pixel cache with
4408% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4409% pixels are transferred, otherwise a NULL is returned.
4410%
4411% The format of the QueueAuthenticNexus() method is:
4412%
cristy5f959472010-05-27 22:19:46 +00004413% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4414% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004415% NexusInfo *nexus_info,ExceptionInfo *exception)
4416%
4417% A description of each parameter follows:
4418%
4419% o image: the image.
4420%
4421% o x,y,columns,rows: These values define the perimeter of a region of
4422% pixels.
4423%
4424% o nexus_info: the cache nexus to set.
4425%
4426% o exception: return any errors or warnings in this structure.
4427%
4428*/
cristybb503372010-05-27 20:51:26 +00004429MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004430 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4431 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004432{
4433 CacheInfo
4434 *cache_info;
4435
4436 MagickOffsetType
4437 offset;
4438
4439 MagickSizeType
4440 number_pixels;
4441
4442 RectangleInfo
4443 region;
4444
4445 /*
4446 Validate pixel cache geometry.
4447 */
4448 cache_info=(CacheInfo *) image->cache;
4449 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4450 {
4451 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4452 "NoPixelsDefinedInCache","`%s'",image->filename);
4453 return((PixelPacket *) NULL);
4454 }
cristybb503372010-05-27 20:51:26 +00004455 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4456 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004457 {
4458 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4459 "PixelsAreNotAuthentic","`%s'",image->filename);
4460 return((PixelPacket *) NULL);
4461 }
4462 offset=(MagickOffsetType) y*cache_info->columns+x;
4463 if (offset < 0)
4464 return((PixelPacket *) NULL);
4465 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4466 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4467 if ((MagickSizeType) offset >= number_pixels)
4468 return((PixelPacket *) NULL);
4469 /*
4470 Return pixel cache.
4471 */
4472 region.x=x;
4473 region.y=y;
4474 region.width=columns;
4475 region.height=rows;
4476 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4477}
4478
4479/*
4480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4481% %
4482% %
4483% %
4484+ 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 %
4485% %
4486% %
4487% %
4488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4489%
4490% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4491% defined by the region rectangle and returns a pointer to the region. This
4492% region is subsequently transferred from the pixel cache with
4493% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4494% pixels are transferred, otherwise a NULL is returned.
4495%
4496% The format of the QueueAuthenticPixelsCache() method is:
4497%
cristybb503372010-05-27 20:51:26 +00004498% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4499% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004500% ExceptionInfo *exception)
4501%
4502% A description of each parameter follows:
4503%
4504% o image: the image.
4505%
4506% o x,y,columns,rows: These values define the perimeter of a region of
4507% pixels.
4508%
4509% o exception: return any errors or warnings in this structure.
4510%
4511*/
cristybb503372010-05-27 20:51:26 +00004512static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4513 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004514 ExceptionInfo *exception)
4515{
4516 CacheInfo
4517 *cache_info;
4518
cristybb503372010-05-27 20:51:26 +00004519 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004520 id;
4521
4522 PixelPacket
4523 *pixels;
4524
4525 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4526 if (cache_info == (Cache) NULL)
4527 return((PixelPacket *) NULL);
4528 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00004529 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004530 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4531 exception);
4532 return(pixels);
4533}
4534
4535/*
4536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4537% %
4538% %
4539% %
4540% Q u e u e A u t h e n t i c P i x e l s %
4541% %
4542% %
4543% %
4544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4545%
4546% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4547% successfully intialized a pointer to a PixelPacket array representing the
4548% region is returned, otherwise NULL is returned. The returned pointer may
4549% point to a temporary working buffer for the pixels or it may point to the
4550% final location of the pixels in memory.
4551%
4552% Write-only access means that any existing pixel values corresponding to
4553% the region are ignored. This is useful if the initial image is being
4554% created from scratch, or if the existing pixel values are to be
4555% completely replaced without need to refer to their pre-existing values.
4556% The application is free to read and write the pixel buffer returned by
4557% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4558% initialize the pixel array values. Initializing pixel array values is the
4559% application's responsibility.
4560%
4561% Performance is maximized if the selected region is part of one row, or
4562% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004563% pixels in-place (without a copy) if the image is in memory, or in a
4564% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004565% by the user.
4566%
4567% Pixels accessed via the returned pointer represent a simple array of type
4568% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4569% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4570% the black color component or the colormap indexes (of type IndexPacket)
4571% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4572% array has been updated, the changes must be saved back to the underlying
4573% image using SyncAuthenticPixels() or they may be lost.
4574%
4575% The format of the QueueAuthenticPixels() method is:
4576%
cristy5f959472010-05-27 22:19:46 +00004577% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4578% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004579% ExceptionInfo *exception)
4580%
4581% A description of each parameter follows:
4582%
4583% o image: the image.
4584%
4585% o x,y,columns,rows: These values define the perimeter of a region of
4586% pixels.
4587%
4588% o exception: return any errors or warnings in this structure.
4589%
4590*/
cristybb503372010-05-27 20:51:26 +00004591MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4592 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004593 ExceptionInfo *exception)
4594{
4595 CacheInfo
4596 *cache_info;
4597
4598 PixelPacket
4599 *pixels;
4600
4601 assert(image != (Image *) NULL);
4602 assert(image->signature == MagickSignature);
4603 if (image->debug != MagickFalse)
4604 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4605 assert(image->cache != (Cache) NULL);
4606 cache_info=(CacheInfo *) image->cache;
4607 assert(cache_info->signature == MagickSignature);
4608 if (cache_info->methods.queue_authentic_pixels_handler ==
4609 (QueueAuthenticPixelsHandler) NULL)
4610 return((PixelPacket *) NULL);
4611 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4612 rows,exception);
4613 return(pixels);
4614}
4615
4616/*
4617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4618% %
4619% %
4620% %
4621+ R e a d P i x e l C a c h e I n d e x e s %
4622% %
4623% %
4624% %
4625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4626%
4627% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4628% the pixel cache.
4629%
4630% The format of the ReadPixelCacheIndexes() method is:
4631%
4632% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4633% NexusInfo *nexus_info,ExceptionInfo *exception)
4634%
4635% A description of each parameter follows:
4636%
4637% o cache_info: the pixel cache.
4638%
4639% o nexus_info: the cache nexus to read the colormap indexes.
4640%
4641% o exception: return any errors or warnings in this structure.
4642%
4643*/
4644static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4645 NexusInfo *nexus_info,ExceptionInfo *exception)
4646{
4647 MagickOffsetType
4648 count,
4649 offset;
4650
4651 MagickSizeType
4652 length,
4653 number_pixels;
4654
4655 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004656 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004657
cristybb503372010-05-27 20:51:26 +00004658 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004659 y;
4660
cristybb503372010-05-27 20:51:26 +00004661 size_t
cristy3ed852e2009-09-05 21:47:34 +00004662 rows;
4663
4664 if (cache_info->debug != MagickFalse)
4665 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4666 cache_info->filename);
4667 if (cache_info->active_index_channel == MagickFalse)
4668 return(MagickFalse);
4669 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4670 return(MagickTrue);
4671 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4672 nexus_info->region.x;
4673 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4674 rows=nexus_info->region.height;
4675 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004676 q=nexus_info->indexes;
4677 switch (cache_info->type)
4678 {
4679 case MemoryCache:
4680 case MapCache:
4681 {
4682 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004683 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004684
4685 /*
4686 Read indexes from memory.
4687 */
cristydd341db2010-03-04 19:06:38 +00004688 if ((cache_info->columns == nexus_info->region.width) &&
4689 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4690 {
4691 length=number_pixels;
4692 rows=1UL;
4693 }
cristy3ed852e2009-09-05 21:47:34 +00004694 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004695 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004696 {
4697 (void) CopyMagickMemory(q,p,(size_t) length);
4698 p+=cache_info->columns;
4699 q+=nexus_info->region.width;
4700 }
4701 break;
4702 }
4703 case DiskCache:
4704 {
4705 /*
4706 Read indexes from disk.
4707 */
4708 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4709 {
4710 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4711 cache_info->cache_filename);
4712 return(MagickFalse);
4713 }
cristydd341db2010-03-04 19:06:38 +00004714 if ((cache_info->columns == nexus_info->region.width) &&
4715 (number_pixels < MagickMaxBufferExtent))
4716 {
4717 length=number_pixels;
4718 rows=1UL;
4719 }
cristy3ed852e2009-09-05 21:47:34 +00004720 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004721 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004722 {
4723 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4724 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4725 if ((MagickSizeType) count < length)
4726 break;
4727 offset+=cache_info->columns;
4728 q+=nexus_info->region.width;
4729 }
cristybb503372010-05-27 20:51:26 +00004730 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004731 {
4732 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4733 cache_info->cache_filename);
4734 return(MagickFalse);
4735 }
4736 break;
4737 }
4738 default:
4739 break;
4740 }
4741 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004742 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004743 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004744 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004745 nexus_info->region.width,(double) nexus_info->region.height,(double)
4746 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004747 return(MagickTrue);
4748}
4749
4750/*
4751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4752% %
4753% %
4754% %
4755+ R e a d P i x e l C a c h e P i x e l s %
4756% %
4757% %
4758% %
4759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4760%
4761% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4762% cache.
4763%
4764% The format of the ReadPixelCachePixels() method is:
4765%
4766% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4767% NexusInfo *nexus_info,ExceptionInfo *exception)
4768%
4769% A description of each parameter follows:
4770%
4771% o cache_info: the pixel cache.
4772%
4773% o nexus_info: the cache nexus to read the pixels.
4774%
4775% o exception: return any errors or warnings in this structure.
4776%
4777*/
4778static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4779 NexusInfo *nexus_info,ExceptionInfo *exception)
4780{
4781 MagickOffsetType
4782 count,
4783 offset;
4784
4785 MagickSizeType
4786 length,
4787 number_pixels;
4788
cristybb503372010-05-27 20:51:26 +00004789 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004790 y;
4791
4792 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004793 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004794
cristybb503372010-05-27 20:51:26 +00004795 size_t
cristy3ed852e2009-09-05 21:47:34 +00004796 rows;
4797
4798 if (cache_info->debug != MagickFalse)
4799 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4800 cache_info->filename);
4801 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4802 return(MagickTrue);
4803 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4804 nexus_info->region.x;
4805 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4806 rows=nexus_info->region.height;
4807 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004808 q=nexus_info->pixels;
4809 switch (cache_info->type)
4810 {
4811 case MemoryCache:
4812 case MapCache:
4813 {
4814 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004815 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004816
4817 /*
4818 Read pixels from memory.
4819 */
cristydd341db2010-03-04 19:06:38 +00004820 if ((cache_info->columns == nexus_info->region.width) &&
4821 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4822 {
4823 length=number_pixels;
4824 rows=1UL;
4825 }
cristy3ed852e2009-09-05 21:47:34 +00004826 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004827 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004828 {
4829 (void) CopyMagickMemory(q,p,(size_t) length);
4830 p+=cache_info->columns;
4831 q+=nexus_info->region.width;
4832 }
4833 break;
4834 }
4835 case DiskCache:
4836 {
4837 /*
4838 Read pixels from disk.
4839 */
4840 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4841 {
4842 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4843 cache_info->cache_filename);
4844 return(MagickFalse);
4845 }
cristydd341db2010-03-04 19:06:38 +00004846 if ((cache_info->columns == nexus_info->region.width) &&
4847 (number_pixels < MagickMaxBufferExtent))
4848 {
4849 length=number_pixels;
4850 rows=1UL;
4851 }
cristybb503372010-05-27 20:51:26 +00004852 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004853 {
4854 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4855 sizeof(*q),length,(unsigned char *) q);
4856 if ((MagickSizeType) count < length)
4857 break;
4858 offset+=cache_info->columns;
4859 q+=nexus_info->region.width;
4860 }
cristybb503372010-05-27 20:51:26 +00004861 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004862 {
4863 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4864 cache_info->cache_filename);
4865 return(MagickFalse);
4866 }
4867 break;
4868 }
4869 default:
4870 break;
4871 }
4872 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004873 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004874 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004875 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004876 nexus_info->region.width,(double) nexus_info->region.height,(double)
4877 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004878 return(MagickTrue);
4879}
4880
4881/*
4882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4883% %
4884% %
4885% %
4886+ R e f e r e n c e P i x e l C a c h e %
4887% %
4888% %
4889% %
4890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4891%
4892% ReferencePixelCache() increments the reference count associated with the
4893% pixel cache returning a pointer to the cache.
4894%
4895% The format of the ReferencePixelCache method is:
4896%
4897% Cache ReferencePixelCache(Cache cache_info)
4898%
4899% A description of each parameter follows:
4900%
4901% o cache_info: the pixel cache.
4902%
4903*/
4904MagickExport Cache ReferencePixelCache(Cache cache)
4905{
4906 CacheInfo
4907 *cache_info;
4908
4909 assert(cache != (Cache *) NULL);
4910 cache_info=(CacheInfo *) cache;
4911 assert(cache_info->signature == MagickSignature);
4912 if (cache_info->debug != MagickFalse)
4913 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4914 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004915 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004916 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004917 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004918 return(cache_info);
4919}
4920
4921/*
4922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4923% %
4924% %
4925% %
4926+ S e t P i x e l C a c h e M e t h o d s %
4927% %
4928% %
4929% %
4930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4931%
4932% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4933%
4934% The format of the SetPixelCacheMethods() method is:
4935%
4936% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4937%
4938% A description of each parameter follows:
4939%
4940% o cache: the pixel cache.
4941%
4942% o cache_methods: Specifies a pointer to a CacheMethods structure.
4943%
4944*/
4945MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4946{
4947 CacheInfo
4948 *cache_info;
4949
4950 GetOneAuthenticPixelFromHandler
4951 get_one_authentic_pixel_from_handler;
4952
4953 GetOneVirtualPixelFromHandler
4954 get_one_virtual_pixel_from_handler;
4955
4956 /*
4957 Set cache pixel methods.
4958 */
4959 assert(cache != (Cache) NULL);
4960 assert(cache_methods != (CacheMethods *) NULL);
4961 cache_info=(CacheInfo *) cache;
4962 assert(cache_info->signature == MagickSignature);
4963 if (cache_info->debug != MagickFalse)
4964 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4965 cache_info->filename);
4966 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4967 cache_info->methods.get_virtual_pixel_handler=
4968 cache_methods->get_virtual_pixel_handler;
4969 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4970 cache_info->methods.destroy_pixel_handler=
4971 cache_methods->destroy_pixel_handler;
4972 if (cache_methods->get_virtual_indexes_from_handler !=
4973 (GetVirtualIndexesFromHandler) NULL)
4974 cache_info->methods.get_virtual_indexes_from_handler=
4975 cache_methods->get_virtual_indexes_from_handler;
4976 if (cache_methods->get_authentic_pixels_handler !=
4977 (GetAuthenticPixelsHandler) NULL)
4978 cache_info->methods.get_authentic_pixels_handler=
4979 cache_methods->get_authentic_pixels_handler;
4980 if (cache_methods->queue_authentic_pixels_handler !=
4981 (QueueAuthenticPixelsHandler) NULL)
4982 cache_info->methods.queue_authentic_pixels_handler=
4983 cache_methods->queue_authentic_pixels_handler;
4984 if (cache_methods->sync_authentic_pixels_handler !=
4985 (SyncAuthenticPixelsHandler) NULL)
4986 cache_info->methods.sync_authentic_pixels_handler=
4987 cache_methods->sync_authentic_pixels_handler;
4988 if (cache_methods->get_authentic_pixels_from_handler !=
4989 (GetAuthenticPixelsFromHandler) NULL)
4990 cache_info->methods.get_authentic_pixels_from_handler=
4991 cache_methods->get_authentic_pixels_from_handler;
4992 if (cache_methods->get_authentic_indexes_from_handler !=
4993 (GetAuthenticIndexesFromHandler) NULL)
4994 cache_info->methods.get_authentic_indexes_from_handler=
4995 cache_methods->get_authentic_indexes_from_handler;
4996 get_one_virtual_pixel_from_handler=
4997 cache_info->methods.get_one_virtual_pixel_from_handler;
4998 if (get_one_virtual_pixel_from_handler !=
4999 (GetOneVirtualPixelFromHandler) NULL)
5000 cache_info->methods.get_one_virtual_pixel_from_handler=
5001 cache_methods->get_one_virtual_pixel_from_handler;
5002 get_one_authentic_pixel_from_handler=
5003 cache_methods->get_one_authentic_pixel_from_handler;
5004 if (get_one_authentic_pixel_from_handler !=
5005 (GetOneAuthenticPixelFromHandler) NULL)
5006 cache_info->methods.get_one_authentic_pixel_from_handler=
5007 cache_methods->get_one_authentic_pixel_from_handler;
5008}
5009
5010/*
5011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5012% %
5013% %
5014% %
5015+ S e t P i x e l C a c h e N e x u s P i x e l s %
5016% %
5017% %
5018% %
5019%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5020%
5021% SetPixelCacheNexusPixels() defines the region of the cache for the
5022% specified cache nexus.
5023%
5024% The format of the SetPixelCacheNexusPixels() method is:
5025%
5026% PixelPacket SetPixelCacheNexusPixels(const Image *image,
5027% const RectangleInfo *region,NexusInfo *nexus_info,
5028% ExceptionInfo *exception)
5029%
5030% A description of each parameter follows:
5031%
5032% o image: the image.
5033%
5034% o region: A pointer to the RectangleInfo structure that defines the
5035% region of this particular cache nexus.
5036%
5037% o nexus_info: the cache nexus to set.
5038%
5039% o exception: return any errors or warnings in this structure.
5040%
5041*/
5042static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5043 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5044{
5045 CacheInfo
5046 *cache_info;
5047
5048 MagickBooleanType
5049 status;
5050
cristy3ed852e2009-09-05 21:47:34 +00005051 MagickSizeType
5052 length,
5053 number_pixels;
5054
5055 if (image->debug != MagickFalse)
5056 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5057 cache_info=(CacheInfo *) image->cache;
5058 assert(cache_info->signature == MagickSignature);
5059 if (cache_info->type == UndefinedCache)
5060 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005061 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005062 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5063 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005064 {
cristybb503372010-05-27 20:51:26 +00005065 ssize_t
cristybad067a2010-02-15 17:20:55 +00005066 x,
5067 y;
cristy3ed852e2009-09-05 21:47:34 +00005068
cristyeaedf062010-05-29 22:36:02 +00005069 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5070 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005071 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5072 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005073 ((nexus_info->region.height == 1UL) ||
5074 ((nexus_info->region.x == 0) &&
5075 ((nexus_info->region.width == cache_info->columns) ||
5076 ((nexus_info->region.width % cache_info->columns) == 0)))))
5077 {
5078 MagickOffsetType
5079 offset;
5080
5081 /*
5082 Pixels are accessed directly from memory.
5083 */
5084 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5085 nexus_info->region.x;
5086 nexus_info->pixels=cache_info->pixels+offset;
5087 nexus_info->indexes=(IndexPacket *) NULL;
5088 if (cache_info->active_index_channel != MagickFalse)
5089 nexus_info->indexes=cache_info->indexes+offset;
5090 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005091 }
5092 }
5093 /*
5094 Pixels are stored in a cache region until they are synced to the cache.
5095 */
5096 number_pixels=(MagickSizeType) nexus_info->region.width*
5097 nexus_info->region.height;
5098 length=number_pixels*sizeof(PixelPacket);
5099 if (cache_info->active_index_channel != MagickFalse)
5100 length+=number_pixels*sizeof(IndexPacket);
5101 if (nexus_info->cache == (PixelPacket *) NULL)
5102 {
5103 nexus_info->length=length;
5104 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5105 if (status == MagickFalse)
5106 return((PixelPacket *) NULL);
5107 }
5108 else
5109 if (nexus_info->length != length)
5110 {
5111 RelinquishCacheNexusPixels(nexus_info);
5112 nexus_info->length=length;
5113 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5114 if (status == MagickFalse)
5115 return((PixelPacket *) NULL);
5116 }
5117 nexus_info->pixels=nexus_info->cache;
5118 nexus_info->indexes=(IndexPacket *) NULL;
5119 if (cache_info->active_index_channel != MagickFalse)
5120 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5121 return(nexus_info->pixels);
5122}
5123
5124/*
5125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5126% %
5127% %
5128% %
5129% 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 %
5130% %
5131% %
5132% %
5133%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5134%
5135% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5136% pixel cache and returns the previous setting. A virtual pixel is any pixel
5137% access that is outside the boundaries of the image cache.
5138%
5139% The format of the SetPixelCacheVirtualMethod() method is:
5140%
5141% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5142% const VirtualPixelMethod virtual_pixel_method)
5143%
5144% A description of each parameter follows:
5145%
5146% o image: the image.
5147%
5148% o virtual_pixel_method: choose the type of virtual pixel.
5149%
5150*/
5151MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5152 const VirtualPixelMethod virtual_pixel_method)
5153{
5154 CacheInfo
5155 *cache_info;
5156
5157 VirtualPixelMethod
5158 method;
5159
5160 assert(image != (Image *) NULL);
5161 assert(image->signature == MagickSignature);
5162 if (image->debug != MagickFalse)
5163 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5164 assert(image->cache != (Cache) NULL);
5165 cache_info=(CacheInfo *) image->cache;
5166 assert(cache_info->signature == MagickSignature);
5167 method=cache_info->virtual_pixel_method;
5168 cache_info->virtual_pixel_method=virtual_pixel_method;
5169 return(method);
5170}
5171
5172/*
5173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5174% %
5175% %
5176% %
5177+ 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 %
5178% %
5179% %
5180% %
5181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5182%
5183% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5184% in-memory or disk cache. The method returns MagickTrue if the pixel region
5185% is synced, otherwise MagickFalse.
5186%
5187% The format of the SyncAuthenticPixelCacheNexus() method is:
5188%
5189% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5190% NexusInfo *nexus_info,ExceptionInfo *exception)
5191%
5192% A description of each parameter follows:
5193%
5194% o image: the image.
5195%
5196% o nexus_info: the cache nexus to sync.
5197%
5198% o exception: return any errors or warnings in this structure.
5199%
5200*/
5201MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5202 NexusInfo *nexus_info,ExceptionInfo *exception)
5203{
5204 CacheInfo
5205 *cache_info;
5206
5207 MagickBooleanType
5208 status;
5209
5210 /*
5211 Transfer pixels to the cache.
5212 */
5213 assert(image != (Image *) NULL);
5214 assert(image->signature == MagickSignature);
5215 if (image->debug != MagickFalse)
5216 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5217 if (image->cache == (Cache) NULL)
5218 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5219 cache_info=(CacheInfo *) image->cache;
5220 if (cache_info->type == UndefinedCache)
5221 return(MagickFalse);
5222 if ((image->clip_mask != (Image *) NULL) &&
5223 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5224 return(MagickFalse);
5225 if ((image->mask != (Image *) NULL) &&
5226 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5227 return(MagickFalse);
5228 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5229 return(MagickTrue);
5230 assert(cache_info->signature == MagickSignature);
5231 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5232 if ((cache_info->active_index_channel != MagickFalse) &&
5233 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5234 return(MagickFalse);
5235 return(status);
5236}
5237
5238/*
5239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5240% %
5241% %
5242% %
5243+ S y n c A u t h e n t i c P i x e l C a c h e %
5244% %
5245% %
5246% %
5247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5248%
5249% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5250% or disk cache. The method returns MagickTrue if the pixel region is synced,
5251% otherwise MagickFalse.
5252%
5253% The format of the SyncAuthenticPixelsCache() method is:
5254%
5255% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5256% ExceptionInfo *exception)
5257%
5258% A description of each parameter follows:
5259%
5260% o image: the image.
5261%
5262% o exception: return any errors or warnings in this structure.
5263%
5264*/
5265static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5266 ExceptionInfo *exception)
5267{
5268 CacheInfo
5269 *cache_info;
5270
cristybb503372010-05-27 20:51:26 +00005271 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005272 id;
5273
5274 MagickBooleanType
5275 status;
5276
5277 cache_info=(CacheInfo *) image->cache;
5278 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00005279 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005280 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5281 exception);
5282 return(status);
5283}
5284
5285/*
5286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5287% %
5288% %
5289% %
5290% S y n c A u t h e n t i c P i x e l s %
5291% %
5292% %
5293% %
5294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5295%
5296% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5297% The method returns MagickTrue if the pixel region is flushed, otherwise
5298% MagickFalse.
5299%
5300% The format of the SyncAuthenticPixels() method is:
5301%
5302% MagickBooleanType SyncAuthenticPixels(Image *image,
5303% ExceptionInfo *exception)
5304%
5305% A description of each parameter follows:
5306%
5307% o image: the image.
5308%
5309% o exception: return any errors or warnings in this structure.
5310%
5311*/
5312MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5313 ExceptionInfo *exception)
5314{
5315 CacheInfo
5316 *cache_info;
5317
5318 assert(image != (Image *) NULL);
5319 assert(image->signature == MagickSignature);
5320 if (image->debug != MagickFalse)
5321 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5322 assert(image->cache != (Cache) NULL);
5323 cache_info=(CacheInfo *) image->cache;
5324 assert(cache_info->signature == MagickSignature);
5325 if (cache_info->methods.sync_authentic_pixels_handler ==
5326 (SyncAuthenticPixelsHandler) NULL)
5327 return(MagickFalse);
5328 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5329}
5330
5331/*
5332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5333% %
5334% %
5335% %
5336+ W r i t e P i x e l C a c h e I n d e x e s %
5337% %
5338% %
5339% %
5340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5341%
5342% WritePixelCacheIndexes() writes the colormap indexes to the specified
5343% region of the pixel cache.
5344%
5345% The format of the WritePixelCacheIndexes() method is:
5346%
5347% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5348% NexusInfo *nexus_info,ExceptionInfo *exception)
5349%
5350% A description of each parameter follows:
5351%
5352% o cache_info: the pixel cache.
5353%
5354% o nexus_info: the cache nexus to write the colormap indexes.
5355%
5356% o exception: return any errors or warnings in this structure.
5357%
5358*/
5359static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5360 NexusInfo *nexus_info,ExceptionInfo *exception)
5361{
5362 MagickOffsetType
5363 count,
5364 offset;
5365
5366 MagickSizeType
5367 length,
5368 number_pixels;
5369
5370 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005371 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005372
cristybb503372010-05-27 20:51:26 +00005373 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005374 y;
5375
cristybb503372010-05-27 20:51:26 +00005376 size_t
cristy3ed852e2009-09-05 21:47:34 +00005377 rows;
5378
5379 if (cache_info->debug != MagickFalse)
5380 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5381 cache_info->filename);
5382 if (cache_info->active_index_channel == MagickFalse)
5383 return(MagickFalse);
5384 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5385 return(MagickTrue);
5386 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5387 nexus_info->region.x;
5388 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5389 rows=nexus_info->region.height;
5390 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005391 p=nexus_info->indexes;
5392 switch (cache_info->type)
5393 {
5394 case MemoryCache:
5395 case MapCache:
5396 {
5397 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005398 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005399
5400 /*
5401 Write indexes to memory.
5402 */
cristydd341db2010-03-04 19:06:38 +00005403 if ((cache_info->columns == nexus_info->region.width) &&
5404 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5405 {
5406 length=number_pixels;
5407 rows=1UL;
5408 }
cristy3ed852e2009-09-05 21:47:34 +00005409 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005410 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005411 {
5412 (void) CopyMagickMemory(q,p,(size_t) length);
5413 p+=nexus_info->region.width;
5414 q+=cache_info->columns;
5415 }
5416 break;
5417 }
5418 case DiskCache:
5419 {
5420 /*
5421 Write indexes to disk.
5422 */
5423 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5424 {
5425 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5426 cache_info->cache_filename);
5427 return(MagickFalse);
5428 }
cristydd341db2010-03-04 19:06:38 +00005429 if ((cache_info->columns == nexus_info->region.width) &&
5430 (number_pixels < MagickMaxBufferExtent))
5431 {
5432 length=number_pixels;
5433 rows=1UL;
5434 }
cristy3ed852e2009-09-05 21:47:34 +00005435 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005436 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005437 {
5438 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5439 sizeof(PixelPacket)+offset*sizeof(*p),length,
5440 (const unsigned char *) p);
5441 if ((MagickSizeType) count < length)
5442 break;
5443 p+=nexus_info->region.width;
5444 offset+=cache_info->columns;
5445 }
cristybb503372010-05-27 20:51:26 +00005446 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005447 {
5448 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5449 cache_info->cache_filename);
5450 return(MagickFalse);
5451 }
5452 break;
5453 }
5454 default:
5455 break;
5456 }
5457 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005458 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005459 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005460 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005461 nexus_info->region.width,(double) nexus_info->region.height,(double)
5462 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005463 return(MagickTrue);
5464}
5465
5466/*
5467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5468% %
5469% %
5470% %
5471+ W r i t e C a c h e P i x e l s %
5472% %
5473% %
5474% %
5475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5476%
5477% WritePixelCachePixels() writes image pixels to the specified region of the
5478% pixel cache.
5479%
5480% The format of the WritePixelCachePixels() method is:
5481%
5482% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5483% NexusInfo *nexus_info,ExceptionInfo *exception)
5484%
5485% A description of each parameter follows:
5486%
5487% o cache_info: the pixel cache.
5488%
5489% o nexus_info: the cache nexus to write the pixels.
5490%
5491% o exception: return any errors or warnings in this structure.
5492%
5493*/
5494static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5495 NexusInfo *nexus_info,ExceptionInfo *exception)
5496{
5497 MagickOffsetType
5498 count,
5499 offset;
5500
5501 MagickSizeType
5502 length,
5503 number_pixels;
5504
cristy3ed852e2009-09-05 21:47:34 +00005505 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005506 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005507
cristybb503372010-05-27 20:51:26 +00005508 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005509 y;
5510
cristybb503372010-05-27 20:51:26 +00005511 size_t
cristy3ed852e2009-09-05 21:47:34 +00005512 rows;
5513
5514 if (cache_info->debug != MagickFalse)
5515 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5516 cache_info->filename);
5517 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5518 return(MagickTrue);
5519 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5520 nexus_info->region.x;
5521 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5522 rows=nexus_info->region.height;
5523 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005524 p=nexus_info->pixels;
5525 switch (cache_info->type)
5526 {
5527 case MemoryCache:
5528 case MapCache:
5529 {
5530 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005531 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005532
5533 /*
5534 Write pixels to memory.
5535 */
cristydd341db2010-03-04 19:06:38 +00005536 if ((cache_info->columns == nexus_info->region.width) &&
5537 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5538 {
5539 length=number_pixels;
5540 rows=1UL;
5541 }
cristy3ed852e2009-09-05 21:47:34 +00005542 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005543 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005544 {
5545 (void) CopyMagickMemory(q,p,(size_t) length);
5546 p+=nexus_info->region.width;
5547 q+=cache_info->columns;
5548 }
5549 break;
5550 }
5551 case DiskCache:
5552 {
5553 /*
5554 Write pixels to disk.
5555 */
5556 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5557 {
5558 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5559 cache_info->cache_filename);
5560 return(MagickFalse);
5561 }
cristydd341db2010-03-04 19:06:38 +00005562 if ((cache_info->columns == nexus_info->region.width) &&
5563 (number_pixels < MagickMaxBufferExtent))
5564 {
5565 length=number_pixels;
5566 rows=1UL;
5567 }
cristybb503372010-05-27 20:51:26 +00005568 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005569 {
5570 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5571 sizeof(*p),length,(const unsigned char *) p);
5572 if ((MagickSizeType) count < length)
5573 break;
5574 p+=nexus_info->region.width;
5575 offset+=cache_info->columns;
5576 }
cristybb503372010-05-27 20:51:26 +00005577 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005578 {
5579 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5580 cache_info->cache_filename);
5581 return(MagickFalse);
5582 }
5583 break;
5584 }
5585 default:
5586 break;
5587 }
5588 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005589 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005590 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005591 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005592 nexus_info->region.width,(double) nexus_info->region.height,(double)
5593 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005594 return(MagickTrue);
5595}