blob: 178886a26c6782f2157d57f58cf34d3cb80cb5e9 [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"
52#include "magick/list.h"
53#include "magick/log.h"
54#include "magick/magick.h"
55#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000056#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000057#include "magick/pixel-private.h"
58#include "magick/quantum.h"
59#include "magick/random_.h"
60#include "magick/resource_.h"
61#include "magick/semaphore.h"
62#include "magick/splay-tree.h"
63#include "magick/string_.h"
64#include "magick/thread-private.h"
65#include "magick/utility.h"
66#if defined(MAGICKCORE_ZLIB_DELEGATE)
67#include "zlib.h"
68#endif
69
70/*
71 Typedef declarations.
72*/
73typedef struct _MagickModulo
74{
75 long
76 quotient,
77 remainder;
78} MagickModulo;
79
80struct _NexusInfo
81{
82 MagickBooleanType
83 mapped;
84
85 RectangleInfo
86 region;
87
88 MagickSizeType
89 length;
90
91 PixelPacket
92 *cache,
93 *pixels;
94
95 IndexPacket
96 *indexes;
97
98 unsigned long
99 signature;
100};
101
102/*
103 Forward declarations.
104*/
105#if defined(__cplusplus) || defined(c_plusplus)
106extern "C" {
107#endif
108
109static const IndexPacket
110 *GetVirtualIndexesFromCache(const Image *);
111
112static const PixelPacket
113 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const long,
114 const long,const unsigned long,const unsigned long,ExceptionInfo *),
115 *GetVirtualPixelsCache(const Image *);
116
117static MagickBooleanType
118 GetOneAuthenticPixelFromCache(Image *,const long,const long,PixelPacket *,
119 ExceptionInfo *),
120 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
121 const long,const long,PixelPacket *,ExceptionInfo *),
122 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
123 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
124 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
125 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
126 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
127 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
128
129static PixelPacket
130 *GetAuthenticPixelsCache(Image *,const long,const long,const unsigned long,
131 const unsigned long,ExceptionInfo *),
132 *QueueAuthenticPixelsCache(Image *,const long,const long,const unsigned long,
133 const unsigned long,ExceptionInfo *),
134 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
135 ExceptionInfo *);
136
137#if defined(__cplusplus) || defined(c_plusplus)
138}
139#endif
140
141/*
142 Global declarations.
143*/
144static volatile MagickBooleanType
145 instantiate_cache = MagickFalse;
146
147static SemaphoreInfo
148 *cache_semaphore = (SemaphoreInfo *) NULL;
149
150static SplayTreeInfo
151 *cache_resources = (SplayTreeInfo *) NULL;
152
153static time_t
154 cache_timer = 0;
155
156/*
157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
158% %
159% %
160% %
161+ A c q u i r e P i x e l C a c h e %
162% %
163% %
164% %
165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166%
167% AcquirePixelCache() acquires a pixel cache.
168%
169% The format of the AcquirePixelCache() method is:
170%
171% Cache AcquirePixelCache(const unsigned long number_threads)
172%
173% A description of each parameter follows:
174%
175% o number_threads: the number of nexus threads.
176%
177*/
178MagickExport Cache AcquirePixelCache(const unsigned long number_threads)
179{
180 CacheInfo
181 *cache_info;
182
183 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
184 if (cache_info == (CacheInfo *) NULL)
185 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
186 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
187 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000188 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000189 cache_info->colorspace=RGBColorspace;
190 cache_info->file=(-1);
191 cache_info->id=GetMagickThreadId();
192 cache_info->number_threads=number_threads;
193 if (number_threads == 0)
194 cache_info->number_threads=GetOpenMPMaximumThreads();
195 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
196 if (cache_info->nexus_info == (NexusInfo **) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 GetPixelCacheMethods(&cache_info->methods);
199 cache_info->reference_count=1;
200 cache_info->semaphore=AllocateSemaphoreInfo();
201 cache_info->disk_semaphore=AllocateSemaphoreInfo();
202 cache_info->debug=IsEventLogging();
203 cache_info->signature=MagickSignature;
204 if ((cache_resources == (SplayTreeInfo *) NULL) &&
205 (instantiate_cache == MagickFalse))
206 {
cristy4e1dff62009-10-25 20:36:03 +0000207 if (cache_semaphore == (SemaphoreInfo *) NULL)
208 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000209 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000210 if ((cache_resources == (SplayTreeInfo *) NULL) &&
211 (instantiate_cache == MagickFalse))
212 {
213 cache_resources=NewSplayTree((int (*)(const void *,const void *))
214 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
215 instantiate_cache=MagickTrue;
216 }
cristyf84a1932010-01-03 18:00:18 +0000217 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000218 }
219 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
220 return((Cache ) cache_info);
221}
222
223/*
224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225% %
226% %
227% %
228% A c q u i r e P i x e l C a c h e N e x u s %
229% %
230% %
231% %
232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233%
234% AcquirePixelCacheNexus() allocates the NexusInfo structure.
235%
236% The format of the AcquirePixelCacheNexus method is:
237%
238% NexusInfo **AcquirePixelCacheNexus(const unsigned long number_threads)
239%
240% A description of each parameter follows:
241%
242% o number_threads: the number of nexus threads.
243%
244*/
245MagickExport NexusInfo **AcquirePixelCacheNexus(
246 const unsigned long number_threads)
247{
248 register long
249 i;
250
251 NexusInfo
252 **nexus_info;
253
254 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
255 sizeof(*nexus_info));
256 if (nexus_info == (NexusInfo **) NULL)
257 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
258 for (i=0; i < (long) number_threads; i++)
259 {
260 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
261 if (nexus_info[i] == (NexusInfo *) NULL)
262 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
263 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
264 nexus_info[i]->signature=MagickSignature;
265 }
266 return(nexus_info);
267}
268
269/*
270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271% %
272% %
273% %
cristyf34a1452009-10-24 22:29:27 +0000274+ C a c h e C o m p o n e n t G e n e s i s %
275% %
276% %
277% %
278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279%
280% CacheComponentGenesis() instantiates the cache component.
281%
282% The format of the CacheComponentGenesis method is:
283%
284% MagickBooleanType CacheComponentGenesis(void)
285%
286*/
287MagickExport MagickBooleanType CacheComponentGenesis(void)
288{
cristy165b6092009-10-26 13:52:10 +0000289 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000290 return(MagickTrue);
291}
292
293/*
294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295% %
296% %
297% %
298+ C a c h e C o m p o n e n t T e r m i n u s %
299% %
300% %
301% %
302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
303%
304% CacheComponentTerminus() destroys the cache component.
305%
306% The format of the CacheComponentTerminus() method is:
307%
308% CacheComponentTerminus(void)
309%
310*/
311MagickExport void CacheComponentTerminus(void)
312{
cristy18b17442009-10-25 18:36:48 +0000313 if (cache_semaphore == (SemaphoreInfo *) NULL)
314 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000315 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000316 if (cache_resources != (SplayTreeInfo *) NULL)
317 cache_resources=DestroySplayTree(cache_resources);
318 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000319 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000320 DestroySemaphoreInfo(&cache_semaphore);
321}
322
323/*
324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325% %
326% %
327% %
cristy3ed852e2009-09-05 21:47:34 +0000328+ C l i p P i x e l C a c h e N e x u s %
329% %
330% %
331% %
332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333%
334% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
335% mask. The method returns MagickTrue if the pixel region is clipped,
336% otherwise MagickFalse.
337%
338% The format of the ClipPixelCacheNexus() method is:
339%
340% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
341% ExceptionInfo *exception)
342%
343% A description of each parameter follows:
344%
345% o image: the image.
346%
347% o nexus_info: the cache nexus to clip.
348%
349% o exception: return any errors or warnings in this structure.
350%
351*/
352static MagickBooleanType ClipPixelCacheNexus(Image *image,
353 NexusInfo *nexus_info,ExceptionInfo *exception)
354{
355 CacheInfo
356 *cache_info;
357
358 MagickSizeType
359 number_pixels;
360
361 NexusInfo
362 **clip_nexus,
363 **image_nexus;
364
365 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000366 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000367
368 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000369 *restrict nexus_indexes,
370 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000371
372 register long
373 i;
374
375 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000376 *restrict p,
377 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000378
379 /*
380 Apply clip mask.
381 */
382 if (image->debug != MagickFalse)
383 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
384 if (image->clip_mask == (Image *) NULL)
385 return(MagickFalse);
386 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
387 if (cache_info == (Cache) NULL)
388 return(MagickFalse);
389 image_nexus=AcquirePixelCacheNexus(1);
390 clip_nexus=AcquirePixelCacheNexus(1);
391 if ((image_nexus == (NexusInfo **) NULL) ||
392 (clip_nexus == (NexusInfo **) NULL))
393 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
394 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
395 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
396 exception);
397 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
398 q=nexus_info->pixels;
399 nexus_indexes=nexus_info->indexes;
400 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
401 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
402 nexus_info->region.height,clip_nexus[0],exception);
403 number_pixels=(MagickSizeType) nexus_info->region.width*
404 nexus_info->region.height;
405 for (i=0; i < (long) number_pixels; i++)
406 {
407 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
408 break;
409 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
410 {
cristyce70c172010-01-07 17:15:30 +0000411 SetRedPixelComponent(q,GetRedPixelComponent(p));
412 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
413 SetBluePixelComponent(q,GetBluePixelComponent(p));
414 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000415 if (cache_info->active_index_channel != MagickFalse)
416 nexus_indexes[i]=indexes[i];
417 }
418 p++;
419 q++;
420 r++;
421 }
422 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
423 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
424 if (i < (long) number_pixels)
425 return(MagickFalse);
426 return(MagickTrue);
427}
428
429/*
430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431% %
432% %
433% %
434+ C l o n e P i x e l C a c h e %
435% %
436% %
437% %
438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439%
440% ClonePixelCache() clones a pixel cache.
441%
442% The format of the ClonePixelCache() method is:
443%
444% Cache ClonePixelCache(const Cache cache)
445%
446% A description of each parameter follows:
447%
448% o cache: the pixel cache.
449%
450*/
451MagickExport Cache ClonePixelCache(const Cache cache)
452{
453 CacheInfo
454 *clone_info;
455
456 const CacheInfo
457 *cache_info;
458
459 assert(cache != (const Cache) NULL);
460 cache_info=(const CacheInfo *) cache;
461 assert(cache_info->signature == MagickSignature);
462 if (cache_info->debug != MagickFalse)
463 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
464 cache_info->filename);
465 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
466 if (clone_info == (Cache) NULL)
467 return((Cache) NULL);
468 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
469 return((Cache ) clone_info);
470}
471
472/*
473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
474% %
475% %
476% %
477+ C l o n e P i x e l C a c h e N e x u s %
478% %
479% %
480% %
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482%
483% ClonePixelCacheNexus() clones the source cache nexus to the destination
484% nexus.
485%
486% The format of the ClonePixelCacheNexus() method is:
487%
488% MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
489% CacheInfo *source,ExceptionInfo *exception)
490%
491% A description of each parameter follows:
492%
493% o destination: the destination cache nexus.
494%
495% o source: the source cache nexus.
496%
497% o exception: return any errors or warnings in this structure.
498%
499*/
500
501static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
502 NexusInfo *nexus_info,ExceptionInfo *exception)
503{
504 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
505 return(MagickFalse);
506 nexus_info->mapped=MagickFalse;
507 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
508 nexus_info->length);
509 if (nexus_info->cache == (PixelPacket *) NULL)
510 {
511 nexus_info->mapped=MagickTrue;
512 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
513 nexus_info->length);
514 }
515 if (nexus_info->cache == (PixelPacket *) NULL)
516 {
517 (void) ThrowMagickException(exception,GetMagickModule(),
518 ResourceLimitError,"MemoryAllocationFailed","`%s'",
519 cache_info->filename);
520 return(MagickFalse);
521 }
522 return(MagickTrue);
523}
524
525static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
526 CacheInfo *source,ExceptionInfo *exception)
527{
528 MagickBooleanType
529 status;
530
531 MagickSizeType
532 number_pixels;
533
534 register long
535 i;
536
537 register const NexusInfo
538 *p;
539
540 register NexusInfo
541 *q;
542
543 status=MagickTrue;
544 for (i=0; i < (long) source->number_threads; i++)
545 {
546 p=source->nexus_info[i];
547 q=destination->nexus_info[i];
548 q->mapped=p->mapped;
549 q->region=p->region;
550 q->length=p->length;
551 q->cache=p->cache;
552 q->pixels=p->pixels;
553 q->indexes=p->indexes;
554 if (p->cache != (PixelPacket *) NULL)
555 {
556 status=AcquireCacheNexusPixels(source,q,exception);
557 if (status != MagickFalse)
558 {
559 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
560 q->pixels=q->cache;
561 q->indexes=(IndexPacket *) NULL;
562 number_pixels=(MagickSizeType) q->region.width*q->region.height;
563 if (p->indexes != (IndexPacket *) NULL)
564 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
565 }
566 }
567 }
568 return(status);
569}
570
571/*
572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
573% %
574% %
575% %
cristy60c44a82009-10-07 00:58:49 +0000576+ 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 +0000577% %
578% %
579% %
580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
581% ClonePixelCachePixels() clones the source pixel cache to the destination
582% cache.
583%
584% The format of the ClonePixelCachePixels() method is:
585%
586% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
587% CacheInfo *source_info,ExceptionInfo *exception)
588%
589% A description of each parameter follows:
590%
591% o cache_info: the pixel cache.
592%
593% o source_info: the source pixel cache.
594%
595% o exception: return any errors or warnings in this structure.
596%
597*/
598
599static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
600{
601 int
602 status;
603
cristyf84a1932010-01-03 18:00:18 +0000604 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000605 status=close(cache_info->file);
606 cache_info->file=(-1);
607 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000608 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000609 return(status == -1 ? MagickFalse : MagickTrue);
610}
611
612static void LimitPixelCacheDescriptors(void)
613{
614 register CacheInfo
615 *p,
616 *q;
617
618 /*
619 Limit # of open file descriptors.
620 */
621 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
622 return;
cristyf84a1932010-01-03 18:00:18 +0000623 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000624 if (cache_resources == (SplayTreeInfo *) NULL)
625 {
cristyf84a1932010-01-03 18:00:18 +0000626 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000627 return;
628 }
629 ResetSplayTreeIterator(cache_resources);
630 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
631 while (p != (CacheInfo *) NULL)
632 {
633 if ((p->type == DiskCache) && (p->file != -1))
634 {
635 if (IsMagickThreadEqual(p->id) != MagickFalse)
636 break;
637 }
638 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
639 }
640 for (q=p; p != (CacheInfo *) NULL; )
641 {
642 if ((p->type == DiskCache) && (p->file != -1) &&
643 (p->timestamp < q->timestamp))
644 {
645 if (IsMagickThreadEqual(p->id) != MagickFalse)
646 q=p;
647 }
648 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
649 }
650 if (q != (CacheInfo *) NULL)
651 (void) ClosePixelCacheOnDisk(q); /* relinquish least recently used cache */
cristyf84a1932010-01-03 18:00:18 +0000652 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000653}
654
655static inline MagickSizeType MagickMax(const MagickSizeType x,
656 const MagickSizeType y)
657{
658 if (x > y)
659 return(x);
660 return(y);
661}
662
663static inline MagickSizeType MagickMin(const MagickSizeType x,
664 const MagickSizeType y)
665{
666 if (x < y)
667 return(x);
668 return(y);
669}
670
671static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
672 const MapMode mode)
673{
674 int
675 file;
676
677 /*
678 Open pixel cache on disk.
679 */
cristyf84a1932010-01-03 18:00:18 +0000680 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000681 if (cache_info->file != -1)
682 {
cristyf84a1932010-01-03 18:00:18 +0000683 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000684 return(MagickTrue); /* cache already open */
685 }
686 LimitPixelCacheDescriptors();
687 if (*cache_info->cache_filename == '\0')
688 file=AcquireUniqueFileResource(cache_info->cache_filename);
689 else
690 switch (mode)
691 {
692 case ReadMode:
693 {
694 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
695 break;
696 }
697 case WriteMode:
698 {
699 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
700 O_EXCL,S_MODE);
701 if (file == -1)
702 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
703 break;
704 }
705 case IOMode:
706 default:
707 {
708 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
709 O_EXCL,S_MODE);
710 if (file == -1)
711 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
712 break;
713 }
714 }
715 if (file == -1)
716 {
cristyf84a1932010-01-03 18:00:18 +0000717 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000718 return(MagickFalse);
719 }
720 (void) AcquireMagickResource(FileResource,1);
721 cache_info->file=file;
722 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000723 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000724 return(MagickTrue);
725}
726
727static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
728 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000729 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000730{
731 register MagickOffsetType
732 i;
733
734 ssize_t
735 count;
736
737#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000738 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000739 cache_info->timestamp=time(0);
740 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
741 {
cristyf84a1932010-01-03 18:00:18 +0000742 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000743 return((MagickOffsetType) -1);
744 }
745#endif
746 count=0;
747 for (i=0; i < (MagickOffsetType) length; i+=count)
748 {
749#if !defined(MAGICKCORE_HAVE_PREAD)
750 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
751 (MagickSizeType) SSIZE_MAX));
752#else
753 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
754 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
755#endif
756 if (count > 0)
757 continue;
758 count=0;
759 if (errno != EINTR)
760 {
761 i=(-1);
762 break;
763 }
764 }
765#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000766 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000767#endif
768 return(i);
769}
770
771static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
772 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000773 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000774{
775 register MagickOffsetType
776 i;
777
778 ssize_t
779 count;
780
781#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000782 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000783 cache_info->timestamp=time(0);
784 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
785 {
cristyf84a1932010-01-03 18:00:18 +0000786 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000787 return((MagickOffsetType) -1);
788 }
789#endif
790 count=0;
791 for (i=0; i < (MagickOffsetType) length; i+=count)
792 {
793#if !defined(MAGICKCORE_HAVE_PWRITE)
794 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
795 (MagickSizeType) SSIZE_MAX));
796#else
797 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
798 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
799#endif
800 if (count > 0)
801 continue;
802 count=0;
803 if (errno != EINTR)
804 {
805 i=(-1);
806 break;
807 }
808 }
809#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000810 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000811#endif
812 return(i);
813}
814
815static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
816 CacheInfo *cache_info,ExceptionInfo *exception)
817{
818 MagickOffsetType
819 count,
820 offset,
821 source_offset;
822
823 MagickSizeType
824 length;
825
826 register long
827 y;
828
829 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000830 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000831
832 unsigned long
833 columns,
834 rows;
835
836 if (cache_info->debug != MagickFalse)
837 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
838 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
839 {
840 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
841 clone_info->cache_filename);
842 return(MagickFalse);
843 }
844 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
845 {
846 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
847 cache_info->cache_filename);
848 return(MagickFalse);
849 }
850 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
851 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
852 if ((clone_info->active_index_channel != MagickFalse) &&
853 (cache_info->active_index_channel != MagickFalse))
854 {
855 register IndexPacket
856 *indexes;
857
858 /*
859 Clone cache indexes.
860 */
861 length=MagickMax(clone_info->columns,cache_info->columns)*
862 sizeof(*indexes);
863 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
864 if (indexes == (IndexPacket *) NULL)
865 {
866 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
867 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
868 return(MagickFalse);
869 }
870 (void) ResetMagickMemory(indexes,0,(size_t) length);
871 length=columns*sizeof(*indexes);
872 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
873 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
874 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
875 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
876 for (y=0; y < (long) rows; y++)
877 {
878 source_offset-=cache_info->columns*sizeof(*indexes);
879 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
880 length,(unsigned char *) indexes);
881 if ((MagickSizeType) count != length)
882 break;
883 offset-=clone_info->columns*sizeof(*indexes);
884 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
885 (unsigned char *) indexes);
886 if ((MagickSizeType) count != length)
887 break;
888 }
889 if (y < (long) rows)
890 {
891 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
892 ThrowFileException(exception,CacheError,"UnableToCloneCache",
893 cache_info->cache_filename);
894 return(MagickFalse);
895 }
896 if (clone_info->columns > cache_info->columns)
897 {
898 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
899 (void) ResetMagickMemory(indexes,0,(size_t) length);
900 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
901 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
902 for (y=0; y < (long) rows; y++)
903 {
904 offset-=clone_info->columns*sizeof(*indexes);
905 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
906 length,(unsigned char *) indexes);
907 if ((MagickSizeType) count != length)
908 break;
909 }
910 if (y < (long) rows)
911 {
912 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
913 ThrowFileException(exception,CacheError,"UnableToCloneCache",
914 cache_info->cache_filename);
915 return(MagickFalse);
916 }
917 }
918 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
919 }
920 /*
921 Clone cache pixels.
922 */
923 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
924 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
925 if (pixels == (PixelPacket *) NULL)
926 {
927 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
928 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
929 return(MagickFalse);
930 }
931 (void) ResetMagickMemory(pixels,0,(size_t) length);
932 length=columns*sizeof(*pixels);
933 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
934 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
935 for (y=0; y < (long) rows; y++)
936 {
937 source_offset-=cache_info->columns*sizeof(*pixels);
938 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
939 length,(unsigned char *) pixels);
940 if ((MagickSizeType) count != length)
941 break;
942 offset-=clone_info->columns*sizeof(*pixels);
943 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
944 (unsigned char *) pixels);
945 if ((MagickSizeType) count != length)
946 break;
947 }
948 if (y < (long) rows)
949 {
950 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
951 ThrowFileException(exception,CacheError,"UnableToCloneCache",
952 cache_info->cache_filename);
953 return(MagickFalse);
954 }
955 if (clone_info->columns > cache_info->columns)
956 {
957 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
958 sizeof(*pixels);
959 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
960 (void) ResetMagickMemory(pixels,0,(size_t) length);
961 for (y=0; y < (long) rows; y++)
962 {
963 offset-=clone_info->columns*sizeof(*pixels);
964 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
965 (unsigned char *) pixels);
966 if ((MagickSizeType) count != length)
967 break;
968 }
969 if (y < (long) rows)
970 {
971 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
972 ThrowFileException(exception,CacheError,"UnableToCloneCache",
973 cache_info->cache_filename);
974 return(MagickFalse);
975 }
976 }
977 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
978 return(MagickTrue);
979}
980
981static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
982 CacheInfo *cache_info,ExceptionInfo *exception)
983{
984 MagickOffsetType
985 count,
986 offset;
987
988 MagickSizeType
989 length;
990
991 register long
992 y;
993
994 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000995 *restrict pixels,
996 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000997
998 unsigned long
999 columns,
1000 rows;
1001
1002 if (cache_info->debug != MagickFalse)
1003 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1004 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1005 {
1006 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1007 cache_info->cache_filename);
1008 return(MagickFalse);
1009 }
1010 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1011 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1012 if ((clone_info->active_index_channel != MagickFalse) &&
1013 (cache_info->active_index_channel != MagickFalse))
1014 {
1015 register IndexPacket
1016 *indexes,
1017 *q;
1018
1019 /*
1020 Clone cache indexes.
1021 */
1022 length=MagickMax(clone_info->columns,cache_info->columns)*
1023 sizeof(*indexes);
1024 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1025 if (indexes == (IndexPacket *) NULL)
1026 {
1027 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1028 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1029 return(MagickFalse);
1030 }
1031 (void) ResetMagickMemory(indexes,0,(size_t) length);
1032 length=columns*sizeof(IndexPacket);
1033 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1034 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1035 q=clone_info->indexes+clone_info->columns*rows;
1036 for (y=0; y < (long) rows; y++)
1037 {
1038 offset-=cache_info->columns*sizeof(IndexPacket);
1039 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1040 length,(unsigned char *) indexes);
1041 if ((MagickSizeType) count != length)
1042 break;
1043 q-=clone_info->columns;
1044 (void) CopyMagickMemory(q,indexes,(size_t) length);
1045 if ((MagickSizeType) count != length)
1046 break;
1047 }
1048 if (y < (long) rows)
1049 {
1050 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1051 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1052 cache_info->cache_filename);
1053 return(MagickFalse);
1054 }
1055 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1056 }
1057 /*
1058 Clone cache pixels.
1059 */
1060 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1061 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1062 if (pixels == (PixelPacket *) NULL)
1063 {
1064 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1065 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1066 return(MagickFalse);
1067 }
1068 (void) ResetMagickMemory(pixels,0,(size_t) length);
1069 length=columns*sizeof(*pixels);
1070 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1071 q=clone_info->pixels+clone_info->columns*rows;
1072 for (y=0; y < (long) rows; y++)
1073 {
1074 offset-=cache_info->columns*sizeof(*pixels);
1075 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1076 (unsigned char *) pixels);
1077 if ((MagickSizeType) count != length)
1078 break;
1079 q-=clone_info->columns;
1080 (void) CopyMagickMemory(q,pixels,(size_t) length);
1081 }
1082 if (y < (long) rows)
1083 {
1084 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1085 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1086 cache_info->cache_filename);
1087 return(MagickFalse);
1088 }
1089 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1090 return(MagickTrue);
1091}
1092
1093static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1094 CacheInfo *cache_info,ExceptionInfo *exception)
1095{
1096 MagickOffsetType
1097 count,
1098 offset;
1099
1100 MagickSizeType
1101 length;
1102
1103 register long
1104 y;
1105
1106 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001107 *restrict p,
1108 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001109
1110 unsigned long
1111 columns,
1112 rows;
1113
1114 if (cache_info->debug != MagickFalse)
1115 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1116 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1117 {
1118 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1119 clone_info->cache_filename);
1120 return(MagickFalse);
1121 }
1122 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1123 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1124 if ((clone_info->active_index_channel != MagickFalse) &&
1125 (cache_info->active_index_channel != MagickFalse))
1126 {
1127 register IndexPacket
1128 *p,
1129 *indexes;
1130
1131 /*
1132 Clone cache indexes.
1133 */
1134 length=MagickMax(clone_info->columns,cache_info->columns)*
1135 sizeof(*indexes);
1136 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1137 if (indexes == (IndexPacket *) NULL)
1138 {
1139 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1140 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1141 return(MagickFalse);
1142 }
1143 (void) ResetMagickMemory(indexes,0,(size_t) length);
1144 length=columns*sizeof(*indexes);
1145 p=cache_info->indexes+cache_info->columns*rows;
1146 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1147 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
1148 for (y=0; y < (long) rows; y++)
1149 {
1150 p-=cache_info->columns;
1151 (void) CopyMagickMemory(indexes,p,(size_t) length);
1152 offset-=clone_info->columns*sizeof(*indexes);
1153 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1154 (unsigned char *) indexes);
1155 if ((MagickSizeType) count != length)
1156 break;
1157 }
1158 if (y < (long) rows)
1159 {
1160 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1161 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1162 cache_info->cache_filename);
1163 return(MagickFalse);
1164 }
1165 if (clone_info->columns > cache_info->columns)
1166 {
1167 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1168 (void) ResetMagickMemory(indexes,0,(size_t) length);
1169 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1170 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
1171 for (y=0; y < (long) rows; y++)
1172 {
1173 offset-=clone_info->columns*sizeof(*indexes);
1174 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1175 length,(unsigned char *) indexes);
1176 if ((MagickSizeType) count != length)
1177 break;
1178 }
1179 if (y < (long) rows)
1180 {
1181 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1182 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1183 cache_info->cache_filename);
1184 return(MagickFalse);
1185 }
1186 }
1187 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1188 }
1189 /*
1190 Clone cache pixels.
1191 */
1192 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1193 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1194 if (pixels == (PixelPacket *) NULL)
1195 {
1196 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1197 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1198 return(MagickFalse);
1199 }
1200 (void) ResetMagickMemory(pixels,0,(size_t) length);
1201 length=columns*sizeof(*pixels);
1202 p=cache_info->pixels+cache_info->columns*rows;
1203 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
1204 for (y=0; y < (long) rows; y++)
1205 {
1206 p-=cache_info->columns;
1207 (void) CopyMagickMemory(pixels,p,(size_t) length);
1208 offset-=clone_info->columns*sizeof(*pixels);
1209 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1210 (unsigned char *) pixels);
1211 if ((MagickSizeType) count != length)
1212 break;
1213 }
1214 if (y < (long) rows)
1215 {
1216 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1217 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1218 cache_info->cache_filename);
1219 return(MagickFalse);
1220 }
1221 if (clone_info->columns > cache_info->columns)
1222 {
1223 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1224 sizeof(*pixels);
1225 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1226 (void) ResetMagickMemory(pixels,0,(size_t) length);
1227 for (y=0; y < (long) rows; y++)
1228 {
1229 offset-=clone_info->columns*sizeof(*pixels);
1230 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1231 (unsigned char *) pixels);
1232 if ((MagickSizeType) count != length)
1233 break;
1234 }
1235 if (y < (long) rows)
1236 {
1237 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1238 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1239 cache_info->cache_filename);
1240 return(MagickFalse);
1241 }
1242 }
1243 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1244 return(MagickTrue);
1245}
1246
1247static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1248 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1249{
1250 register long
1251 y;
1252
1253 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001254 *restrict pixels,
1255 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001256
1257 size_t
1258 length;
1259
1260 unsigned long
1261 columns,
1262 rows;
1263
1264 if (cache_info->debug != MagickFalse)
1265 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1266 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1267 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1268 if ((clone_info->active_index_channel != MagickFalse) &&
1269 (cache_info->active_index_channel != MagickFalse))
1270 {
1271 register IndexPacket
1272 *indexes,
1273 *source_indexes;
1274
1275 /*
1276 Clone cache indexes.
1277 */
1278 length=columns*sizeof(*indexes);
1279 if (clone_info->columns == cache_info->columns)
1280 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1281 length*rows);
1282 else
1283 {
1284 source_indexes=cache_info->indexes+cache_info->columns*rows;
1285 indexes=clone_info->indexes+clone_info->columns*rows;
1286 for (y=0; y < (long) rows; y++)
1287 {
1288 source_indexes-=cache_info->columns;
1289 indexes-=clone_info->columns;
1290 (void) CopyMagickMemory(indexes,source_indexes,length);
1291 }
1292 if (clone_info->columns > cache_info->columns)
1293 {
1294 length=(clone_info->columns-cache_info->columns)*
1295 sizeof(*indexes);
1296 indexes=clone_info->indexes+clone_info->columns*rows+
1297 cache_info->columns;
1298 for (y=0; y < (long) rows; y++)
1299 {
1300 indexes-=clone_info->columns;
1301 (void) ResetMagickMemory(indexes,0,length);
1302 }
1303 }
1304 }
1305 }
1306 /*
1307 Clone cache pixels.
1308 */
1309 length=columns*sizeof(*pixels);
1310 if (clone_info->columns == cache_info->columns)
1311 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1312 else
1313 {
1314 source_pixels=cache_info->pixels+cache_info->columns*rows;
1315 pixels=clone_info->pixels+clone_info->columns*rows;
1316 for (y=0; y < (long) rows; y++)
1317 {
1318 source_pixels-=cache_info->columns;
1319 pixels-=clone_info->columns;
1320 (void) CopyMagickMemory(pixels,source_pixels,length);
1321 }
1322 if (clone_info->columns > cache_info->columns)
1323 {
1324 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1325 pixels=clone_info->pixels+clone_info->columns*rows+
1326 cache_info->columns;
1327 for (y=0; y < (long) rows; y++)
1328 {
1329 pixels-=clone_info->columns;
1330 (void) ResetMagickMemory(pixels,0,length);
1331 }
1332 }
1333 }
1334 return(MagickTrue);
1335}
1336
1337static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1338 CacheInfo *cache_info,ExceptionInfo *exception)
1339{
1340 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1341 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1342 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1343 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1344 if (cache_info->type == DiskCache)
1345 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1346 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1347}
1348
1349/*
1350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1351% %
1352% %
1353% %
1354+ C l o n e P i x e l C a c h e M e t h o d s %
1355% %
1356% %
1357% %
1358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359%
1360% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1361% another.
1362%
1363% The format of the ClonePixelCacheMethods() method is:
1364%
1365% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1366%
1367% A description of each parameter follows:
1368%
1369% o clone: Specifies a pointer to a Cache structure.
1370%
1371% o cache: the pixel cache.
1372%
1373*/
1374MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1375{
1376 CacheInfo
1377 *cache_info,
1378 *source_info;
1379
1380 assert(clone != (Cache) NULL);
1381 source_info=(CacheInfo *) clone;
1382 assert(source_info->signature == MagickSignature);
1383 if (source_info->debug != MagickFalse)
1384 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1385 source_info->filename);
1386 assert(cache != (Cache) NULL);
1387 cache_info=(CacheInfo *) cache;
1388 assert(cache_info->signature == MagickSignature);
1389 source_info->methods=cache_info->methods;
1390}
1391
1392/*
1393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1394% %
1395% %
1396% %
1397+ D e s t r o y I m a g e P i x e l C a c h e %
1398% %
1399% %
1400% %
1401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402%
1403% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1404%
1405% The format of the DestroyImagePixelCache() method is:
1406%
1407% void DestroyImagePixelCache(Image *image)
1408%
1409% A description of each parameter follows:
1410%
1411% o image: the image.
1412%
1413*/
1414static void DestroyImagePixelCache(Image *image)
1415{
1416 assert(image != (Image *) NULL);
1417 assert(image->signature == MagickSignature);
1418 if (image->debug != MagickFalse)
1419 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1420 if (image->cache == (void *) NULL)
1421 return;
1422 image->cache=DestroyPixelCache(image->cache);
1423}
1424
1425/*
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427% %
1428% %
1429% %
1430+ D e s t r o y I m a g e P i x e l s %
1431% %
1432% %
1433% %
1434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1435%
1436% DestroyImagePixels() deallocates memory associated with the pixel cache.
1437%
1438% The format of the DestroyImagePixels() method is:
1439%
1440% void DestroyImagePixels(Image *image)
1441%
1442% A description of each parameter follows:
1443%
1444% o image: the image.
1445%
1446*/
1447MagickExport void DestroyImagePixels(Image *image)
1448{
1449 CacheInfo
1450 *cache_info;
1451
1452 assert(image != (const Image *) NULL);
1453 assert(image->signature == MagickSignature);
1454 if (image->debug != MagickFalse)
1455 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1456 assert(image->cache != (Cache) NULL);
1457 cache_info=(CacheInfo *) image->cache;
1458 assert(cache_info->signature == MagickSignature);
1459 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1460 return;
1461 cache_info->methods.destroy_pixel_handler(image);
1462}
1463
1464/*
1465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1466% %
1467% %
1468% %
1469+ D e s t r o y P i x e l C a c h e %
1470% %
1471% %
1472% %
1473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1474%
1475% DestroyPixelCache() deallocates memory associated with the pixel cache.
1476%
1477% The format of the DestroyPixelCache() method is:
1478%
1479% Cache DestroyPixelCache(Cache cache)
1480%
1481% A description of each parameter follows:
1482%
1483% o cache: the pixel cache.
1484%
1485*/
1486
1487static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1488{
1489 switch (cache_info->type)
1490 {
1491 case MemoryCache:
1492 {
1493 if (cache_info->mapped == MagickFalse)
1494 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1495 cache_info->pixels);
1496 else
1497 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1498 (size_t) cache_info->length);
1499 RelinquishMagickResource(MemoryResource,cache_info->length);
1500 break;
1501 }
1502 case MapCache:
1503 {
1504 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1505 cache_info->length);
1506 RelinquishMagickResource(MapResource,cache_info->length);
1507 }
1508 case DiskCache:
1509 {
1510 if (cache_info->file != -1)
1511 (void) ClosePixelCacheOnDisk(cache_info);
1512 RelinquishMagickResource(DiskResource,cache_info->length);
1513 break;
1514 }
1515 default:
1516 break;
1517 }
1518 cache_info->type=UndefinedCache;
1519 cache_info->mapped=MagickFalse;
1520 cache_info->indexes=(IndexPacket *) NULL;
1521}
1522
1523MagickExport Cache DestroyPixelCache(Cache cache)
1524{
1525 CacheInfo
1526 *cache_info;
1527
cristy3ed852e2009-09-05 21:47:34 +00001528 assert(cache != (Cache) NULL);
1529 cache_info=(CacheInfo *) cache;
1530 assert(cache_info->signature == MagickSignature);
1531 if (cache_info->debug != MagickFalse)
1532 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1533 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001534 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001535 cache_info->reference_count--;
1536 if (cache_info->reference_count != 0)
1537 {
cristyf84a1932010-01-03 18:00:18 +00001538 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001539 return((Cache) NULL);
1540 }
cristyf84a1932010-01-03 18:00:18 +00001541 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001542 if (cache_resources != (SplayTreeInfo *) NULL)
1543 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001544 if (cache_info->debug != MagickFalse)
1545 {
1546 char
1547 message[MaxTextExtent];
1548
1549 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1550 cache_info->filename);
1551 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1552 }
cristyc2e1bdd2009-09-10 23:43:34 +00001553 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1554 (cache_info->type != DiskCache)))
1555 RelinquishPixelCachePixels(cache_info);
1556 else
1557 {
1558 RelinquishPixelCachePixels(cache_info);
1559 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1560 }
cristy3ed852e2009-09-05 21:47:34 +00001561 *cache_info->cache_filename='\0';
1562 if (cache_info->nexus_info != (NexusInfo **) NULL)
1563 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1564 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001565 if (cache_info->random_info != (RandomInfo *) NULL)
1566 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1567 cache_info->signature=(~MagickSignature);
1568 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1569 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1570 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1571 DestroySemaphoreInfo(&cache_info->semaphore);
1572 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1573 cache=(Cache) NULL;
1574 return(cache);
1575}
1576
1577/*
1578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1579% %
1580% %
1581% %
1582+ D e s t r o y P i x e l C a c h e N e x u s %
1583% %
1584% %
1585% %
1586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587%
1588% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1589%
1590% The format of the DestroyPixelCacheNexus() method is:
1591%
1592% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1593% const unsigned long number_threads)
1594%
1595% A description of each parameter follows:
1596%
1597% o nexus_info: the nexus to destroy.
1598%
1599% o number_threads: the number of nexus threads.
1600%
1601*/
1602
1603static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1604{
1605 if (nexus_info->mapped == MagickFalse)
1606 (void) RelinquishMagickMemory(nexus_info->cache);
1607 else
1608 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1609 nexus_info->cache=(PixelPacket *) NULL;
1610 nexus_info->pixels=(PixelPacket *) NULL;
1611 nexus_info->indexes=(IndexPacket *) NULL;
1612 nexus_info->length=0;
1613 nexus_info->mapped=MagickFalse;
1614}
1615
1616MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1617 const unsigned long number_threads)
1618{
1619 register long
1620 i;
1621
1622 assert(nexus_info != (NexusInfo **) NULL);
1623 for (i=0; i < (long) number_threads; i++)
1624 {
1625 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1626 RelinquishCacheNexusPixels(nexus_info[i]);
1627 nexus_info[i]->signature=(~MagickSignature);
1628 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1629 }
1630 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1631 return(nexus_info);
1632}
1633
1634/*
1635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636% %
1637% %
1638% %
cristy3ed852e2009-09-05 21:47:34 +00001639+ 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 %
1640% %
1641% %
1642% %
1643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1644%
1645% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1646% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1647%
1648% The format of the GetAuthenticIndexesFromCache() method is:
1649%
1650% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1651%
1652% A description of each parameter follows:
1653%
1654% o image: the image.
1655%
1656*/
1657static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1658{
1659 CacheInfo
1660 *cache_info;
1661
1662 IndexPacket
1663 *indexes;
1664
1665 long
1666 id;
1667
1668 if (image->debug != MagickFalse)
1669 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1670 cache_info=(CacheInfo *) image->cache;
1671 id=GetOpenMPThreadId();
1672 assert(id < (long) cache_info->number_threads);
1673 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1674 return(indexes);
1675}
1676
1677/*
1678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1679% %
1680% %
1681% %
1682% G e t A u t h e n t i c I n d e x Q u e u e %
1683% %
1684% %
1685% %
1686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1687%
1688% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1689% indexes associated with the last call to QueueAuthenticPixels() or
1690% GetVirtualPixels(). NULL is returned if the black channel or colormap
1691% indexes are not available.
1692%
1693% The format of the GetAuthenticIndexQueue() method is:
1694%
1695% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1696%
1697% A description of each parameter follows:
1698%
1699% o image: the image.
1700%
1701*/
1702MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1703{
1704 CacheInfo
1705 *cache_info;
1706
1707 assert(image != (const Image *) NULL);
1708 assert(image->signature == MagickSignature);
1709 if (image->debug != MagickFalse)
1710 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1711 assert(image->cache != (Cache) NULL);
1712 cache_info=(CacheInfo *) image->cache;
1713 assert(cache_info->signature == MagickSignature);
1714 if (cache_info->methods.get_authentic_indexes_from_handler ==
1715 (GetAuthenticIndexesFromHandler) NULL)
1716 return((IndexPacket *) NULL);
1717 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1718}
1719
1720/*
1721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1722% %
1723% %
1724% %
1725+ 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 %
1726% %
1727% %
1728% %
1729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1730%
1731% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1732% disk pixel cache as defined by the geometry parameters. A pointer to the
1733% pixels is returned if the pixels are transferred, otherwise a NULL is
1734% returned.
1735%
1736% The format of the GetAuthenticPixelCacheNexus() method is:
1737%
1738% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1739% const long y,const unsigned long columns,const unsigned long rows,
1740% NexusInfo *nexus_info,ExceptionInfo *exception)
1741%
1742% A description of each parameter follows:
1743%
1744% o image: the image.
1745%
1746% o x,y,columns,rows: These values define the perimeter of a region of
1747% pixels.
1748%
1749% o nexus_info: the cache nexus to return.
1750%
1751% o exception: return any errors or warnings in this structure.
1752%
1753*/
1754
1755static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1756 NexusInfo *nexus_info)
1757{
1758 MagickOffsetType
1759 offset;
1760
1761 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1762 nexus_info->region.x;
1763 if (nexus_info->pixels != (cache_info->pixels+offset))
1764 return(MagickFalse);
1765 return(MagickTrue);
1766}
1767
1768MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1769 const long y,const unsigned long columns,const unsigned long rows,
1770 NexusInfo *nexus_info,ExceptionInfo *exception)
1771{
1772 CacheInfo
1773 *cache_info;
1774
1775 PixelPacket
1776 *pixels;
1777
1778 /*
1779 Transfer pixels from the cache.
1780 */
1781 assert(image != (Image *) NULL);
1782 assert(image->signature == MagickSignature);
1783 if (image->debug != MagickFalse)
1784 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1785 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1786 if (pixels == (PixelPacket *) NULL)
1787 return((PixelPacket *) NULL);
1788 cache_info=(CacheInfo *) image->cache;
1789 assert(cache_info->signature == MagickSignature);
1790 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1791 return(pixels);
1792 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1793 return((PixelPacket *) NULL);
1794 if (cache_info->active_index_channel != MagickFalse)
1795 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1796 return((PixelPacket *) NULL);
1797 return(pixels);
1798}
1799
1800/*
1801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802% %
1803% %
1804% %
1805+ 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 %
1806% %
1807% %
1808% %
1809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1810%
1811% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1812% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1813%
1814% The format of the GetAuthenticPixelsFromCache() method is:
1815%
1816% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1817%
1818% A description of each parameter follows:
1819%
1820% o image: the image.
1821%
1822*/
1823static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1824{
1825 CacheInfo
1826 *cache_info;
1827
1828 long
1829 id;
1830
1831 PixelPacket
1832 *pixels;
1833
1834 if (image->debug != MagickFalse)
1835 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1836 cache_info=(CacheInfo *) image->cache;
1837 id=GetOpenMPThreadId();
1838 assert(id < (long) cache_info->number_threads);
1839 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1840 return(pixels);
1841}
1842
1843/*
1844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1845% %
1846% %
1847% %
1848% G e t A u t h e n t i c P i x e l Q u e u e %
1849% %
1850% %
1851% %
1852%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1853%
1854% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1855% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1856%
1857% The format of the GetAuthenticPixelQueue() method is:
1858%
1859% PixelPacket *GetAuthenticPixelQueue(const Image image)
1860%
1861% A description of each parameter follows:
1862%
1863% o image: the image.
1864%
1865*/
1866MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1867{
1868 CacheInfo
1869 *cache_info;
1870
1871 assert(image != (const Image *) NULL);
1872 assert(image->signature == MagickSignature);
1873 if (image->debug != MagickFalse)
1874 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1875 assert(image->cache != (Cache) NULL);
1876 cache_info=(CacheInfo *) image->cache;
1877 assert(cache_info->signature == MagickSignature);
1878 if (cache_info->methods.get_authentic_pixels_from_handler ==
1879 (GetAuthenticPixelsFromHandler) NULL)
1880 return((PixelPacket *) NULL);
1881 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1882}
1883
1884/*
1885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1886% %
1887% %
1888% %
1889% G e t A u t h e n t i c P i x e l s %
1890% %
1891% %
1892% %
1893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1894%
1895% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1896% region is successfully accessed, a pointer to a PixelPacket array
1897% representing the region is returned, otherwise NULL is returned.
1898%
1899% The returned pointer may point to a temporary working copy of the pixels
1900% or it may point to the original pixels in memory. Performance is maximized
1901% if the selected region is part of one row, or one or more full rows, since
1902% then there is opportunity to access the pixels in-place (without a copy)
1903% if the image is in RAM, or in a memory-mapped file. The returned pointer
1904% should *never* be deallocated by the user.
1905%
1906% Pixels accessed via the returned pointer represent a simple array of type
1907% PixelPacket. If the image type is CMYK or if the storage class is
1908% PseduoClass, call GetAuthenticIndexQueue() after invoking
1909% GetAuthenticPixels() to obtain the black color component or colormap indexes
1910% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1911% (and/or IndexPacket) array has been updated, the changes must be saved back
1912% to the underlying image using SyncAuthenticPixels() or they may be lost.
1913%
1914% The format of the GetAuthenticPixels() method is:
1915%
1916% PixelPacket *GetAuthenticPixels(Image *image,const long x,const long y,
1917% const unsigned long columns,const unsigned long rows,
1918% ExceptionInfo *exception)
1919%
1920% A description of each parameter follows:
1921%
1922% o image: the image.
1923%
1924% o x,y,columns,rows: These values define the perimeter of a region of
1925% pixels.
1926%
1927% o exception: return any errors or warnings in this structure.
1928%
1929*/
1930MagickExport PixelPacket *GetAuthenticPixels(Image *image,const long x,
1931 const long y,const unsigned long columns,const unsigned long rows,
1932 ExceptionInfo *exception)
1933{
1934 CacheInfo
1935 *cache_info;
1936
1937 PixelPacket
1938 *pixels;
1939
1940 assert(image != (Image *) NULL);
1941 assert(image->signature == MagickSignature);
1942 if (image->debug != MagickFalse)
1943 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1944 assert(image->cache != (Cache) NULL);
1945 cache_info=(CacheInfo *) image->cache;
1946 assert(cache_info->signature == MagickSignature);
1947 if (cache_info->methods.get_authentic_pixels_handler ==
1948 (GetAuthenticPixelsHandler) NULL)
1949 return((PixelPacket *) NULL);
1950 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1951 rows,exception);
1952 return(pixels);
1953}
1954
1955/*
1956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1957% %
1958% %
1959% %
1960+ G e t A u t h e n t i c P i x e l s C a c h e %
1961% %
1962% %
1963% %
1964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1965%
1966% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1967% as defined by the geometry parameters. A pointer to the pixels is returned
1968% if the pixels are transferred, otherwise a NULL is returned.
1969%
1970% The format of the GetAuthenticPixelsCache() method is:
1971%
1972% PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
1973% const long y,const unsigned long columns,const unsigned long rows,
1974% ExceptionInfo *exception)
1975%
1976% A description of each parameter follows:
1977%
1978% o image: the image.
1979%
1980% o x,y,columns,rows: These values define the perimeter of a region of
1981% pixels.
1982%
1983% o exception: return any errors or warnings in this structure.
1984%
1985*/
1986static PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
1987 const long y,const unsigned long columns,const unsigned long rows,
1988 ExceptionInfo *exception)
1989{
1990 CacheInfo
1991 *cache_info;
1992
1993 long
1994 id;
1995
1996 PixelPacket
1997 *pixels;
1998
1999 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2000 if (cache_info == (Cache) NULL)
2001 return((PixelPacket *) NULL);
2002 id=GetOpenMPThreadId();
2003 assert(id < (long) cache_info->number_threads);
2004 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2005 cache_info->nexus_info[id],exception);
2006 return(pixels);
2007}
2008
2009/*
2010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2011% %
2012% %
2013% %
2014+ G e t I m a g e E x t e n t %
2015% %
2016% %
2017% %
2018%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2019%
2020% GetImageExtent() returns the extent of the pixels associated with the
2021% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2022%
2023% The format of the GetImageExtent() method is:
2024%
2025% MagickSizeType GetImageExtent(const Image *image)
2026%
2027% A description of each parameter follows:
2028%
2029% o image: the image.
2030%
2031*/
2032MagickExport MagickSizeType GetImageExtent(const Image *image)
2033{
2034 CacheInfo
2035 *cache_info;
2036
2037 long
2038 id;
2039
2040 MagickSizeType
2041 extent;
2042
2043 assert(image != (Image *) NULL);
2044 assert(image->signature == MagickSignature);
2045 if (image->debug != MagickFalse)
2046 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2047 assert(image->cache != (Cache) NULL);
2048 cache_info=(CacheInfo *) image->cache;
2049 assert(cache_info->signature == MagickSignature);
2050 id=GetOpenMPThreadId();
2051 assert(id < (long) cache_info->number_threads);
2052 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2053 return(extent);
2054}
2055
2056/*
2057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2058% %
2059% %
2060% %
2061+ G e t I m a g e P i x e l C a c h e %
2062% %
2063% %
2064% %
2065%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2066%
2067% GetImagePixelCache() ensures that there is only a single reference to the
2068% pixel cache to be modified, updating the provided cache pointer to point to
2069% a clone of the original pixel cache if necessary.
2070%
2071% The format of the GetImagePixelCache method is:
2072%
2073% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2074% ExceptionInfo *exception)
2075%
2076% A description of each parameter follows:
2077%
2078% o image: the image.
2079%
2080% o clone: any value other than MagickFalse clones the cache pixels.
2081%
2082% o exception: return any errors or warnings in this structure.
2083%
2084*/
2085
2086static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2087{
2088 CacheInfo
2089 *cache_info;
2090
2091 /*
2092 Does the image match the pixel cache morphology?
2093 */
2094 cache_info=(CacheInfo *) image->cache;
2095 if ((image->storage_class != cache_info->storage_class) ||
2096 (image->colorspace != cache_info->colorspace) ||
2097 (image->columns != cache_info->columns) ||
2098 (image->rows != cache_info->rows) ||
2099 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2100 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2101 return(MagickFalse);
2102 return(MagickTrue);
2103}
2104
2105MagickExport Cache GetImagePixelCache(Image *image,
2106 const MagickBooleanType clone,ExceptionInfo *exception)
2107{
2108 CacheInfo
2109 *cache_info;
2110
2111 MagickSizeType
2112 time_limit;
2113
2114 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002115 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002116 status;
2117
2118 if (image->debug != MagickFalse)
2119 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2120 status=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00002121 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002122 time_limit=GetMagickResourceLimit(TimeResource);
2123 if (cache_timer == 0)
2124 cache_timer=time((time_t *) NULL);
2125 if ((time_limit != MagickResourceInfinity) &&
2126 ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit))
2127 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2128 assert(image->cache != (Cache) NULL);
2129 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002130 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00002131 LockSemaphoreInfo(cache_info->semaphore);
cristy01b7eb02009-09-10 23:10:14 +00002132 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002133 {
2134 Image
2135 clone_image;
2136
2137 CacheInfo
2138 *clone_info;
2139
2140 /*
2141 Clone pixel cache.
2142 */
2143 clone_image=(*image);
2144 clone_image.cache=ClonePixelCache(cache_info);
2145 clone_info=(CacheInfo *) clone_image.cache;
2146 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
2147 if (status != MagickFalse)
2148 {
2149 status=OpenPixelCache(&clone_image,IOMode,exception);
2150 if (status != MagickFalse)
2151 {
2152 if (clone != MagickFalse)
2153 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2154 if (status != MagickFalse)
2155 {
cristy4320e0e2009-09-10 15:00:08 +00002156 destroy=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002157 image->cache=clone_image.cache;
2158 }
2159 }
2160 }
2161 }
cristyf84a1932010-01-03 18:00:18 +00002162 UnlockSemaphoreInfo(cache_info->semaphore);
cristy4320e0e2009-09-10 15:00:08 +00002163 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002164 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002165 if (status != MagickFalse)
2166 {
2167 /*
2168 Ensure the image matches the pixel cache morphology.
2169 */
2170 image->taint=MagickTrue;
2171 image->type=UndefinedType;
2172 if (image->colorspace == GRAYColorspace)
2173 image->colorspace=RGBColorspace;
2174 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2175 status=OpenPixelCache(image,IOMode,exception);
2176 }
cristyf84a1932010-01-03 18:00:18 +00002177 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002178 if (status == MagickFalse)
2179 return((Cache) NULL);
2180 return(image->cache);
2181}
2182
2183/*
2184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2185% %
2186% %
2187% %
2188% G e t O n e A u t h e n t i c P i x e l %
2189% %
2190% %
2191% %
2192%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2193%
2194% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2195% location. The image background color is returned if an error occurs.
2196%
2197% The format of the GetOneAuthenticPixel() method is:
2198%
2199% MagickBooleanType GetOneAuthenticPixel(const Image image,const long x,
2200% const long y,PixelPacket *pixel,ExceptionInfo *exception)
2201%
2202% A description of each parameter follows:
2203%
2204% o image: the image.
2205%
2206% o x,y: These values define the location of the pixel to return.
2207%
2208% o pixel: return a pixel at the specified (x,y) location.
2209%
2210% o exception: return any errors or warnings in this structure.
2211%
2212*/
2213MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,const long x,
2214 const long y,PixelPacket *pixel,ExceptionInfo *exception)
2215{
2216 CacheInfo
2217 *cache_info;
2218
2219 GetOneAuthenticPixelFromHandler
2220 get_one_authentic_pixel_from_handler;
2221
2222 MagickBooleanType
2223 status;
2224
2225 assert(image != (Image *) NULL);
2226 assert(image->signature == MagickSignature);
2227 if (image->debug != MagickFalse)
2228 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2229 assert(image->cache != (Cache) NULL);
2230 cache_info=(CacheInfo *) image->cache;
2231 assert(cache_info->signature == MagickSignature);
2232 *pixel=image->background_color;
2233 get_one_authentic_pixel_from_handler=
2234 cache_info->methods.get_one_authentic_pixel_from_handler;
2235 if (get_one_authentic_pixel_from_handler ==
2236 (GetOneAuthenticPixelFromHandler) NULL)
2237 return(MagickFalse);
2238 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2239 pixel,exception);
2240 return(status);
2241}
2242
2243/*
2244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2245% %
2246% %
2247% %
2248+ 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 %
2249% %
2250% %
2251% %
2252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2253%
2254% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2255% location. The image background color is returned if an error occurs.
2256%
2257% The format of the GetOneAuthenticPixelFromCache() method is:
2258%
2259% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2260% const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2261%
2262% A description of each parameter follows:
2263%
2264% o image: the image.
2265%
2266% o x,y: These values define the location of the pixel to return.
2267%
2268% o pixel: return a pixel at the specified (x,y) location.
2269%
2270% o exception: return any errors or warnings in this structure.
2271%
2272*/
2273static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2274 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2275{
2276 PixelPacket
2277 *pixels;
2278
2279 if (image->debug != MagickFalse)
2280 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2281 *pixel=image->background_color;
2282 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2283 if (pixels == (PixelPacket *) NULL)
2284 return(MagickFalse);
2285 *pixel=(*pixels);
2286 return(MagickTrue);
2287}
2288
2289/*
2290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2291% %
2292% %
2293% %
2294% G e t O n e V i r t u a l M a g i c k P i x e l %
2295% %
2296% %
2297% %
2298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2299%
2300% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2301% location. The image background color is returned if an error occurs. If
2302% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2303%
2304% The format of the GetOneVirtualMagickPixel() method is:
2305%
2306% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2307% const long x,const long y,MagickPixelPacket *pixel,
2308% ExceptionInfo exception)
2309%
2310% A description of each parameter follows:
2311%
2312% o image: the image.
2313%
2314% o x,y: these values define the location of the pixel to return.
2315%
2316% o pixel: return a pixel at the specified (x,y) location.
2317%
2318% o exception: return any errors or warnings in this structure.
2319%
2320*/
2321MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2322 const long x,const long y,MagickPixelPacket *pixel,ExceptionInfo *exception)
2323{
2324 CacheInfo
2325 *cache_info;
2326
2327 register const IndexPacket
2328 *indexes;
2329
2330 register const PixelPacket
2331 *p;
2332
2333 assert(image != (const Image *) NULL);
2334 assert(image->signature == MagickSignature);
2335 assert(image->cache != (Cache) NULL);
2336 cache_info=(CacheInfo *) image->cache;
2337 assert(cache_info->signature == MagickSignature);
2338 GetMagickPixelPacket(image,pixel);
2339 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2340 exception);
2341 if (p == (const PixelPacket *) NULL)
2342 return(MagickFalse);
2343 indexes=GetVirtualIndexQueue(image);
2344 SetMagickPixelPacket(image,p,indexes,pixel);
2345 return(MagickTrue);
2346}
2347
2348/*
2349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2350% %
2351% %
2352% %
2353% G e t O n e V i r t u a l M e t h o d P i x e l %
2354% %
2355% %
2356% %
2357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2358%
2359% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2360% location as defined by specified pixel method. The image background color
2361% is returned if an error occurs. If you plan to modify the pixel, use
2362% GetOneAuthenticPixel() instead.
2363%
2364% The format of the GetOneVirtualMethodPixel() method is:
2365%
2366% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2367% const VirtualPixelMethod virtual_pixel_method,const long x,
2368% const long y,Pixelpacket *pixel,ExceptionInfo exception)
2369%
2370% A description of each parameter follows:
2371%
2372% o image: the image.
2373%
2374% o virtual_pixel_method: the virtual pixel method.
2375%
2376% o x,y: These values define the location of the pixel to return.
2377%
2378% o pixel: return a pixel at the specified (x,y) location.
2379%
2380% o exception: return any errors or warnings in this structure.
2381%
2382*/
2383MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2384 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2385 PixelPacket *pixel,ExceptionInfo *exception)
2386{
2387 GetOneVirtualPixelFromHandler
2388 get_one_virtual_pixel_from_handler;
2389
2390 CacheInfo
2391 *cache_info;
2392
2393 MagickBooleanType
2394 status;
2395
2396 assert(image != (const Image *) NULL);
2397 assert(image->signature == MagickSignature);
2398 assert(image->cache != (Cache) NULL);
2399 cache_info=(CacheInfo *) image->cache;
2400 assert(cache_info->signature == MagickSignature);
2401 *pixel=image->background_color;
2402 get_one_virtual_pixel_from_handler=
2403 cache_info->methods.get_one_virtual_pixel_from_handler;
2404 if (get_one_virtual_pixel_from_handler ==
2405 (GetOneVirtualPixelFromHandler) NULL)
2406 return(MagickFalse);
2407 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2408 pixel,exception);
2409 return(status);
2410}
2411
2412/*
2413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2414% %
2415% %
2416% %
2417% G e t O n e V i r t u a l P i x e l %
2418% %
2419% %
2420% %
2421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2422%
2423% GetOneVirtualPixel() returns a single virtual pixel at the specified
2424% (x,y) location. The image background color is returned if an error occurs.
2425% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2426%
2427% The format of the GetOneVirtualPixel() method is:
2428%
2429% MagickBooleanType GetOneVirtualPixel(const Image image,const long x,
2430% const long y,PixelPacket *pixel,ExceptionInfo exception)
2431%
2432% A description of each parameter follows:
2433%
2434% o image: the image.
2435%
2436% o x,y: These values define the location of the pixel to return.
2437%
2438% o pixel: return a pixel at the specified (x,y) location.
2439%
2440% o exception: return any errors or warnings in this structure.
2441%
2442*/
2443MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2444 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2445{
2446 GetOneVirtualPixelFromHandler
2447 get_one_virtual_pixel_from_handler;
2448
2449 CacheInfo
2450 *cache_info;
2451
2452 MagickBooleanType
2453 status;
2454
2455 assert(image != (const Image *) NULL);
2456 assert(image->signature == MagickSignature);
2457 assert(image->cache != (Cache) NULL);
2458 cache_info=(CacheInfo *) image->cache;
2459 assert(cache_info->signature == MagickSignature);
2460 *pixel=image->background_color;
2461 get_one_virtual_pixel_from_handler=
2462 cache_info->methods.get_one_virtual_pixel_from_handler;
2463 if (get_one_virtual_pixel_from_handler ==
2464 (GetOneVirtualPixelFromHandler) NULL)
2465 return(MagickFalse);
2466 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2467 image),x,y,pixel,exception);
2468 return(status);
2469}
2470
2471/*
2472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2473% %
2474% %
2475% %
2476+ 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 %
2477% %
2478% %
2479% %
2480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2481%
2482% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2483% specified (x,y) location. The image background color is returned if an
2484% error occurs.
2485%
2486% The format of the GetOneVirtualPixelFromCache() method is:
2487%
2488% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2489% const VirtualPixelPacket method,const long x,const long y,
2490% PixelPacket *pixel,ExceptionInfo *exception)
2491%
2492% A description of each parameter follows:
2493%
2494% o image: the image.
2495%
2496% o virtual_pixel_method: the virtual pixel method.
2497%
2498% o x,y: These values define the location of the pixel to return.
2499%
2500% o pixel: return a pixel at the specified (x,y) location.
2501%
2502% o exception: return any errors or warnings in this structure.
2503%
2504*/
2505static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2506 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2507 PixelPacket *pixel,ExceptionInfo *exception)
2508{
2509 const PixelPacket
2510 *pixels;
2511
2512 *pixel=image->background_color;
2513 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2514 if (pixels == (const PixelPacket *) NULL)
2515 return(MagickFalse);
2516 *pixel=(*pixels);
2517 return(MagickTrue);
2518}
2519
2520/*
2521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2522% %
2523% %
2524% %
2525+ G e t P i x e l C a c h e C o l o r s p a c e %
2526% %
2527% %
2528% %
2529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2530%
2531% GetPixelCacheColorspace() returns the class type of the pixel cache.
2532%
2533% The format of the GetPixelCacheColorspace() method is:
2534%
2535% Colorspace GetPixelCacheColorspace(Cache cache)
2536%
2537% A description of each parameter follows:
2538%
2539% o cache: the pixel cache.
2540%
2541*/
2542MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2543{
2544 CacheInfo
2545 *cache_info;
2546
2547 assert(cache != (Cache) NULL);
2548 cache_info=(CacheInfo *) cache;
2549 assert(cache_info->signature == MagickSignature);
2550 if (cache_info->debug != MagickFalse)
2551 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2552 cache_info->filename);
2553 return(cache_info->colorspace);
2554}
2555
2556/*
2557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2558% %
2559% %
2560% %
2561+ G e t P i x e l C a c h e M e t h o d s %
2562% %
2563% %
2564% %
2565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2566%
2567% GetPixelCacheMethods() initializes the CacheMethods structure.
2568%
2569% The format of the GetPixelCacheMethods() method is:
2570%
2571% void GetPixelCacheMethods(CacheMethods *cache_methods)
2572%
2573% A description of each parameter follows:
2574%
2575% o cache_methods: Specifies a pointer to a CacheMethods structure.
2576%
2577*/
2578MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2579{
2580 assert(cache_methods != (CacheMethods *) NULL);
2581 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2582 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2583 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2584 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2585 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2586 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2587 cache_methods->get_authentic_indexes_from_handler=
2588 GetAuthenticIndexesFromCache;
2589 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2590 cache_methods->get_one_authentic_pixel_from_handler=
2591 GetOneAuthenticPixelFromCache;
2592 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2593 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2594 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2595}
2596
2597/*
2598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2599% %
2600% %
2601% %
2602+ G e t P i x e l C a c h e N e x u s E x t e n t %
2603% %
2604% %
2605% %
2606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2607%
2608% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2609% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2610%
2611% The format of the GetPixelCacheNexusExtent() method is:
2612%
2613% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2614% NexusInfo *nexus_info)
2615%
2616% A description of each parameter follows:
2617%
2618% o nexus_info: the nexus info.
2619%
2620*/
2621MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2622 NexusInfo *nexus_info)
2623{
2624 CacheInfo
2625 *cache_info;
2626
2627 MagickSizeType
2628 extent;
2629
2630 if (cache == (Cache) NULL)
2631 return(0);
2632 cache_info=(CacheInfo *) cache;
2633 assert(cache_info->signature == MagickSignature);
2634 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2635 if (extent == 0)
2636 return((MagickSizeType) cache_info->columns*cache_info->rows);
2637 return(extent);
2638}
2639
2640/*
2641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2642% %
2643% %
2644% %
2645+ 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 %
2646% %
2647% %
2648% %
2649%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2650%
2651% GetPixelCacheNexusIndexes() returns the indexes associated with the
2652% specified cache nexus.
2653%
2654% The format of the GetPixelCacheNexusIndexes() method is:
2655%
2656% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2657% NexusInfo *nexus_info)
2658%
2659% A description of each parameter follows:
2660%
2661% o cache: the pixel cache.
2662%
2663% o nexus_info: the cache nexus to return the colormap indexes.
2664%
2665*/
2666MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2667 NexusInfo *nexus_info)
2668{
2669 CacheInfo
2670 *cache_info;
2671
2672 if (cache == (Cache) NULL)
2673 return((IndexPacket *) NULL);
2674 cache_info=(CacheInfo *) cache;
2675 assert(cache_info->signature == MagickSignature);
2676 if (cache_info->storage_class == UndefinedClass)
2677 return((IndexPacket *) NULL);
2678 return(nexus_info->indexes);
2679}
2680
2681/*
2682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2683% %
2684% %
2685% %
2686+ G e t P i x e l C a c h e N e x u s P i x e l s %
2687% %
2688% %
2689% %
2690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2691%
2692% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2693% cache nexus.
2694%
2695% The format of the GetPixelCacheNexusPixels() method is:
2696%
2697% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2698% NexusInfo *nexus_info)
2699%
2700% A description of each parameter follows:
2701%
2702% o cache: the pixel cache.
2703%
2704% o nexus_info: the cache nexus to return the pixels.
2705%
2706*/
2707MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2708 NexusInfo *nexus_info)
2709{
2710 CacheInfo
2711 *cache_info;
2712
2713 if (cache == (Cache) NULL)
2714 return((PixelPacket *) NULL);
2715 cache_info=(CacheInfo *) cache;
2716 assert(cache_info->signature == MagickSignature);
2717 if (cache_info->debug != MagickFalse)
2718 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2719 cache_info->filename);
2720 if (cache_info->storage_class == UndefinedClass)
2721 return((PixelPacket *) NULL);
2722 return(nexus_info->pixels);
2723}
2724
2725/*
2726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2727% %
2728% %
2729% %
cristy056ba772010-01-02 23:33:54 +00002730+ G e t P i x e l C a c h e P i x e l s %
2731% %
2732% %
2733% %
2734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2735%
2736% GetPixelCachePixels() returns the pixels associated with the specified image.
2737%
2738% The format of the GetPixelCachePixels() method is:
2739%
cristyf84a1932010-01-03 18:00:18 +00002740% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2741% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002742%
2743% A description of each parameter follows:
2744%
2745% o image: the image.
2746%
2747% o length: the pixel cache length.
2748%
cristyf84a1932010-01-03 18:00:18 +00002749% o exception: return any errors or warnings in this structure.
2750%
cristy056ba772010-01-02 23:33:54 +00002751*/
cristyf84a1932010-01-03 18:00:18 +00002752MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2753 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002754{
2755 CacheInfo
2756 *cache_info;
2757
2758 assert(image != (const Image *) NULL);
2759 assert(image->signature == MagickSignature);
2760 if (image->debug != MagickFalse)
2761 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2762 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002763 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002764 assert(cache_info->signature == MagickSignature);
2765 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002766 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002767 return((void *) NULL);
2768 *length=cache_info->length;
2769 return((void *) cache_info->pixels);
2770}
2771
2772/*
2773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2774% %
2775% %
2776% %
cristyb32b90a2009-09-07 21:45:48 +00002777+ 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 +00002778% %
2779% %
2780% %
2781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2782%
2783% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2784%
2785% The format of the GetPixelCacheStorageClass() method is:
2786%
2787% ClassType GetPixelCacheStorageClass(Cache cache)
2788%
2789% A description of each parameter follows:
2790%
2791% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2792%
2793% o cache: the pixel cache.
2794%
2795*/
2796MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2797{
2798 CacheInfo
2799 *cache_info;
2800
2801 assert(cache != (Cache) NULL);
2802 cache_info=(CacheInfo *) cache;
2803 assert(cache_info->signature == MagickSignature);
2804 if (cache_info->debug != MagickFalse)
2805 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2806 cache_info->filename);
2807 return(cache_info->storage_class);
2808}
2809
2810/*
2811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2812% %
2813% %
2814% %
cristyb32b90a2009-09-07 21:45:48 +00002815+ G e t P i x e l C a c h e T i l e S i z e %
2816% %
2817% %
2818% %
2819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2820%
2821% GetPixelCacheTileSize() returns the pixel cache tile size.
2822%
2823% The format of the GetPixelCacheTileSize() method is:
2824%
2825% void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2826% unsigned long *height)
2827%
2828% A description of each parameter follows:
2829%
2830% o image: the image.
2831%
2832% o width: the optimize cache tile width in pixels.
2833%
2834% o height: the optimize cache tile height in pixels.
2835%
2836*/
2837MagickExport void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2838 unsigned long *height)
2839{
2840 CacheInfo
2841 *cache_info;
2842
2843 assert(image != (Image *) NULL);
2844 assert(image->signature == MagickSignature);
2845 if (image->debug != MagickFalse)
2846 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2847 assert(image->cache != (Cache) NULL);
2848 cache_info=(CacheInfo *) image->cache;
2849 assert(cache_info->signature == MagickSignature);
2850 *width=2048UL/sizeof(PixelPacket);
2851 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002852 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002853 *height=(*width);
2854}
2855
2856/*
2857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2858% %
2859% %
2860% %
2861+ G e t P i x e l C a c h e T y p e %
2862% %
2863% %
2864% %
2865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2866%
2867% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2868%
2869% The format of the GetPixelCacheType() method is:
2870%
2871% CacheType GetPixelCacheType(const Image *image)
2872%
2873% A description of each parameter follows:
2874%
2875% o image: the image.
2876%
2877*/
2878MagickExport CacheType GetPixelCacheType(const Image *image)
2879{
2880 CacheInfo
2881 *cache_info;
2882
2883 assert(image != (Image *) NULL);
2884 assert(image->signature == MagickSignature);
2885 if (image->debug != MagickFalse)
2886 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2887 assert(image->cache != (Cache) NULL);
2888 cache_info=(CacheInfo *) image->cache;
2889 assert(cache_info->signature == MagickSignature);
2890 return(cache_info->type);
2891}
2892
2893/*
2894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2895% %
2896% %
2897% %
cristy3ed852e2009-09-05 21:47:34 +00002898+ 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 %
2899% %
2900% %
2901% %
2902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2903%
2904% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2905% pixel cache. A virtual pixel is any pixel access that is outside the
2906% boundaries of the image cache.
2907%
2908% The format of the GetPixelCacheVirtualMethod() method is:
2909%
2910% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2911%
2912% A description of each parameter follows:
2913%
2914% o image: the image.
2915%
2916*/
2917MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2918{
2919 CacheInfo
2920 *cache_info;
2921
2922 assert(image != (Image *) NULL);
2923 assert(image->signature == MagickSignature);
2924 if (image->debug != MagickFalse)
2925 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2926 assert(image->cache != (Cache) NULL);
2927 cache_info=(CacheInfo *) image->cache;
2928 assert(cache_info->signature == MagickSignature);
2929 return(cache_info->virtual_pixel_method);
2930}
2931
2932/*
2933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2934% %
2935% %
2936% %
2937+ 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 %
2938% %
2939% %
2940% %
2941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2942%
2943% GetVirtualIndexesFromCache() returns the indexes associated with the last
2944% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2945%
2946% The format of the GetVirtualIndexesFromCache() method is:
2947%
2948% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2949%
2950% A description of each parameter follows:
2951%
2952% o image: the image.
2953%
2954*/
2955static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2956{
2957 CacheInfo
2958 *cache_info;
2959
2960 const IndexPacket
2961 *indexes;
2962
2963 long
2964 id;
2965
2966 if (image->debug != MagickFalse)
2967 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2968 cache_info=(CacheInfo *) image->cache;
2969 id=GetOpenMPThreadId();
2970 assert(id < (long) cache_info->number_threads);
2971 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
2972 return(indexes);
2973}
2974
2975/*
2976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2977% %
2978% %
2979% %
2980+ 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 %
2981% %
2982% %
2983% %
2984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2985%
2986% GetVirtualIndexesFromNexus() returns the indexes associated with the
2987% specified cache nexus.
2988%
2989% The format of the GetVirtualIndexesFromNexus() method is:
2990%
2991% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2992% NexusInfo *nexus_info)
2993%
2994% A description of each parameter follows:
2995%
2996% o cache: the pixel cache.
2997%
2998% o nexus_info: the cache nexus to return the colormap indexes.
2999%
3000*/
3001MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3002 NexusInfo *nexus_info)
3003{
3004 CacheInfo
3005 *cache_info;
3006
3007 if (cache == (Cache) NULL)
3008 return((IndexPacket *) NULL);
3009 cache_info=(CacheInfo *) cache;
3010 assert(cache_info->signature == MagickSignature);
3011 if (cache_info->storage_class == UndefinedClass)
3012 return((IndexPacket *) NULL);
3013 return(nexus_info->indexes);
3014}
3015
3016/*
3017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3018% %
3019% %
3020% %
3021% G e t V i r t u a l I n d e x Q u e u e %
3022% %
3023% %
3024% %
3025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3026%
3027% GetVirtualIndexQueue() returns the virtual black channel or the
3028% colormap indexes associated with the last call to QueueAuthenticPixels() or
3029% GetVirtualPixels(). NULL is returned if the black channel or colormap
3030% indexes are not available.
3031%
3032% The format of the GetVirtualIndexQueue() method is:
3033%
3034% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3035%
3036% A description of each parameter follows:
3037%
3038% o image: the image.
3039%
3040*/
3041MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3042{
3043 CacheInfo
3044 *cache_info;
3045
3046 assert(image != (const Image *) NULL);
3047 assert(image->signature == MagickSignature);
3048 if (image->debug != MagickFalse)
3049 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3050 assert(image->cache != (Cache) NULL);
3051 cache_info=(CacheInfo *) image->cache;
3052 assert(cache_info->signature == MagickSignature);
3053 if (cache_info->methods.get_virtual_indexes_from_handler ==
3054 (GetVirtualIndexesFromHandler) NULL)
3055 return((IndexPacket *) NULL);
3056 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3057}
3058
3059/*
3060%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3061% %
3062% %
3063% %
3064+ 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 %
3065% %
3066% %
3067% %
3068%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3069%
3070% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3071% pixel cache as defined by the geometry parameters. A pointer to the pixels
3072% is returned if the pixels are transferred, otherwise a NULL is returned.
3073%
3074% The format of the GetVirtualPixelsFromNexus() method is:
3075%
3076% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3077% const VirtualPixelMethod method,const long x,const long y,
3078% const unsigned long columns,const unsigned long rows,
3079% NexusInfo *nexus_info,ExceptionInfo *exception)
3080%
3081% A description of each parameter follows:
3082%
3083% o image: the image.
3084%
3085% o virtual_pixel_method: the virtual pixel method.
3086%
3087% o x,y,columns,rows: These values define the perimeter of a region of
3088% pixels.
3089%
3090% o nexus_info: the cache nexus to acquire.
3091%
3092% o exception: return any errors or warnings in this structure.
3093%
3094*/
3095
3096static long
3097 DitherMatrix[64] =
3098 {
3099 0, 48, 12, 60, 3, 51, 15, 63,
3100 32, 16, 44, 28, 35, 19, 47, 31,
3101 8, 56, 4, 52, 11, 59, 7, 55,
3102 40, 24, 36, 20, 43, 27, 39, 23,
3103 2, 50, 14, 62, 1, 49, 13, 61,
3104 34, 18, 46, 30, 33, 17, 45, 29,
3105 10, 58, 6, 54, 9, 57, 5, 53,
3106 42, 26, 38, 22, 41, 25, 37, 21
3107 };
3108
cristy222528c2010-01-09 23:36:34 +00003109static inline long DitherX(const long x,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003110{
3111 long
3112 index;
3113
3114 index=x+DitherMatrix[x & 0x07]-32L;
3115 if (index < 0L)
3116 return(0L);
3117 if (index >= (long) columns)
3118 return((long) columns-1L);
3119 return(index);
3120}
3121
cristy222528c2010-01-09 23:36:34 +00003122static inline long DitherY(const long y,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003123{
3124 long
3125 index;
3126
3127 index=y+DitherMatrix[y & 0x07]-32L;
3128 if (index < 0L)
3129 return(0L);
3130 if (index >= (long) rows)
3131 return((long) rows-1L);
3132 return(index);
3133}
3134
cristy222528c2010-01-09 23:36:34 +00003135static inline long EdgeX(const long x,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003136{
3137 if (x < 0L)
3138 return(0L);
3139 if (x >= (long) columns)
cristy97be2b92010-01-09 23:37:55 +00003140 return((long) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003141 return(x);
3142}
3143
cristy222528c2010-01-09 23:36:34 +00003144static inline long EdgeY(const long y,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003145{
3146 if (y < 0L)
3147 return(0L);
3148 if (y >= (long) rows)
cristy97be2b92010-01-09 23:37:55 +00003149 return((long) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003150 return(y);
3151}
3152
cristy222528c2010-01-09 23:36:34 +00003153static inline long RandomX(RandomInfo *random_info,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003154{
3155 return((long) (columns*GetPseudoRandomValue(random_info)));
3156}
3157
cristy222528c2010-01-09 23:36:34 +00003158static inline long RandomY(RandomInfo *random_info,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003159{
3160 return((long) (rows*GetPseudoRandomValue(random_info)));
3161}
3162
3163/*
3164 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3165 returns not only the quotient (tile the offset falls in) but also the positive
3166 remainer within that tile such that 0 <= remainder < extent. This method is
3167 essentially a ldiv() using a floored modulo division rather than the normal
3168 default truncated modulo division.
3169*/
3170static inline MagickModulo VirtualPixelModulo(const long offset,
3171 const unsigned long extent)
3172{
3173 MagickModulo
3174 modulo;
3175
3176 modulo.quotient=offset/(long) extent;
3177 if (offset < 0L)
3178 modulo.quotient--;
3179 modulo.remainder=offset-modulo.quotient*(long) extent;
3180 return(modulo);
3181}
3182
3183MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3184 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3185 const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
3186 ExceptionInfo *exception)
3187{
3188 CacheInfo
3189 *cache_info;
3190
3191 MagickOffsetType
3192 offset;
3193
3194 MagickSizeType
3195 length,
3196 number_pixels;
3197
3198 NexusInfo
3199 **virtual_nexus;
3200
3201 PixelPacket
3202 *pixels,
3203 virtual_pixel;
3204
3205 RectangleInfo
3206 region;
3207
3208 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003209 *restrict nexus_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003210
3211 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003212 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003213
3214 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003215 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003216
3217 register long
3218 u,
3219 v;
3220
3221 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003222 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003223
3224 /*
3225 Acquire pixels.
3226 */
3227 if (image->debug != MagickFalse)
3228 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3229 cache_info=(CacheInfo *) image->cache;
3230 if (cache_info->type == UndefinedCache)
3231 return((const PixelPacket *) NULL);
3232 region.x=x;
3233 region.y=y;
3234 region.width=columns;
3235 region.height=rows;
3236 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3237 if (pixels == (PixelPacket *) NULL)
3238 return((const PixelPacket *) NULL);
3239 offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
cristy4789f0d2010-01-10 00:01:06 +00003240 length=(MagickSizeType) (region.height-1L)*cache_info->columns+
3241 region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003242 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3243 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3244 if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
3245 (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
3246 {
3247 MagickBooleanType
3248 status;
3249
3250 /*
3251 Pixel request is inside cache extents.
3252 */
3253 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3254 return(pixels);
3255 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3256 if (status == MagickFalse)
3257 return((const PixelPacket *) NULL);
3258 if ((cache_info->storage_class == PseudoClass) ||
3259 (cache_info->colorspace == CMYKColorspace))
3260 {
3261 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3262 if (status == MagickFalse)
3263 return((const PixelPacket *) NULL);
3264 }
3265 return(pixels);
3266 }
3267 /*
3268 Pixel request is outside cache extents.
3269 */
3270 q=pixels;
3271 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3272 virtual_nexus=AcquirePixelCacheNexus(1);
3273 if (virtual_nexus == (NexusInfo **) NULL)
3274 {
3275 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3276 "UnableToGetCacheNexus","`%s'",image->filename);
3277 return((const PixelPacket *) NULL);
3278 }
3279 switch (virtual_pixel_method)
3280 {
3281 case BlackVirtualPixelMethod:
3282 {
cristy4789f0d2010-01-10 00:01:06 +00003283 SetRedPixelComponent(&virtual_pixel,0);
3284 SetGreenPixelComponent(&virtual_pixel,0);
3285 SetBluePixelComponent(&virtual_pixel,0);
3286 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003287 break;
3288 }
3289 case GrayVirtualPixelMethod:
3290 {
cristy4789f0d2010-01-10 00:01:06 +00003291 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3292 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3293 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3294 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003295 break;
3296 }
3297 case TransparentVirtualPixelMethod:
3298 {
cristy4789f0d2010-01-10 00:01:06 +00003299 SetRedPixelComponent(&virtual_pixel,0);
3300 SetGreenPixelComponent(&virtual_pixel,0);
3301 SetBluePixelComponent(&virtual_pixel,0);
3302 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003303 break;
3304 }
3305 case MaskVirtualPixelMethod:
3306 case WhiteVirtualPixelMethod:
3307 {
cristy4789f0d2010-01-10 00:01:06 +00003308 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3309 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3310 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3311 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003312 break;
3313 }
3314 default:
3315 {
3316 virtual_pixel=image->background_color;
3317 break;
3318 }
3319 }
3320 for (v=0; v < (long) rows; v++)
3321 {
3322 for (u=0; u < (long) columns; u+=length)
3323 {
3324 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3325 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
3326 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
3327 {
3328 MagickModulo
3329 x_modulo,
3330 y_modulo;
3331
3332 /*
3333 Transfer a single pixel.
3334 */
3335 length=(MagickSizeType) 1;
3336 switch (virtual_pixel_method)
3337 {
3338 case BackgroundVirtualPixelMethod:
3339 case ConstantVirtualPixelMethod:
3340 case BlackVirtualPixelMethod:
3341 case GrayVirtualPixelMethod:
3342 case TransparentVirtualPixelMethod:
3343 case MaskVirtualPixelMethod:
3344 case WhiteVirtualPixelMethod:
3345 {
3346 p=(&virtual_pixel);
3347 break;
3348 }
3349 case EdgeVirtualPixelMethod:
3350 default:
3351 {
3352 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003353 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003354 1UL,1UL,virtual_nexus[0],exception);
3355 break;
3356 }
3357 case RandomVirtualPixelMethod:
3358 {
3359 if (cache_info->random_info == (RandomInfo *) NULL)
3360 cache_info->random_info=AcquireRandomInfo();
3361 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003362 RandomX(cache_info->random_info,cache_info->columns),
3363 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003364 virtual_nexus[0],exception);
3365 break;
3366 }
3367 case DitherVirtualPixelMethod:
3368 {
3369 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003370 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003371 1UL,1UL,virtual_nexus[0],exception);
3372 break;
3373 }
3374 case TileVirtualPixelMethod:
3375 {
3376 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3377 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3378 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3379 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3380 exception);
3381 break;
3382 }
3383 case MirrorVirtualPixelMethod:
3384 {
3385 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3386 if ((x_modulo.quotient & 0x01) == 1L)
3387 x_modulo.remainder=(long) cache_info->columns-
3388 x_modulo.remainder-1L;
3389 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3390 if ((y_modulo.quotient & 0x01) == 1L)
3391 y_modulo.remainder=(long) cache_info->rows-
3392 y_modulo.remainder-1L;
3393 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3394 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3395 exception);
3396 break;
3397 }
3398 case CheckerTileVirtualPixelMethod:
3399 {
3400 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3401 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3402 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3403 {
3404 p=(&virtual_pixel);
3405 break;
3406 }
3407 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3408 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3409 exception);
3410 break;
3411 }
3412 case HorizontalTileVirtualPixelMethod:
3413 {
3414 if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
3415 {
3416 p=(&virtual_pixel);
3417 break;
3418 }
3419 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3420 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3422 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3423 exception);
3424 break;
3425 }
3426 case VerticalTileVirtualPixelMethod:
3427 {
3428 if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
3429 {
3430 p=(&virtual_pixel);
3431 break;
3432 }
3433 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3434 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3435 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3436 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3437 exception);
3438 break;
3439 }
3440 case HorizontalTileEdgeVirtualPixelMethod:
3441 {
3442 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3443 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003444 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003445 virtual_nexus[0],exception);
3446 break;
3447 }
3448 case VerticalTileEdgeVirtualPixelMethod:
3449 {
3450 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3451 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003452 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003453 virtual_nexus[0],exception);
3454 break;
3455 }
3456 }
3457 if (p == (const PixelPacket *) NULL)
3458 break;
3459 *q++=(*p);
3460 if (indexes != (IndexPacket *) NULL)
3461 {
3462 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
3463 virtual_nexus[0]);
3464 if (nexus_indexes != (const IndexPacket *) NULL)
3465 *indexes++=(*nexus_indexes);
3466 }
3467 continue;
3468 }
3469 /*
3470 Transfer a run of pixels.
3471 */
3472 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3473 (unsigned long) length,1UL,virtual_nexus[0],exception);
3474 if (p == (const PixelPacket *) NULL)
3475 break;
3476 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3477 q+=length;
3478 if (indexes != (IndexPacket *) NULL)
3479 {
3480 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3481 if (nexus_indexes != (const IndexPacket *) NULL)
3482 {
3483 (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
3484 sizeof(*nexus_indexes));
3485 indexes+=length;
3486 }
3487 }
3488 }
3489 }
3490 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3491 return(pixels);
3492}
3493
3494/*
3495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3496% %
3497% %
3498% %
3499+ G e t V i r t u a l P i x e l C a c h e %
3500% %
3501% %
3502% %
3503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3504%
3505% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3506% cache as defined by the geometry parameters. A pointer to the pixels
3507% is returned if the pixels are transferred, otherwise a NULL is returned.
3508%
3509% The format of the GetVirtualPixelCache() method is:
3510%
3511% const PixelPacket *GetVirtualPixelCache(const Image *image,
3512% const VirtualPixelMethod virtual_pixel_method,const long x,
3513% const long y,const unsigned long columns,const unsigned long rows,
3514% ExceptionInfo *exception)
3515%
3516% A description of each parameter follows:
3517%
3518% o image: the image.
3519%
3520% o virtual_pixel_method: the virtual pixel method.
3521%
3522% o x,y,columns,rows: These values define the perimeter of a region of
3523% pixels.
3524%
3525% o exception: return any errors or warnings in this structure.
3526%
3527*/
3528static const PixelPacket *GetVirtualPixelCache(const Image *image,
3529 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3530 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
3531{
3532 CacheInfo
3533 *cache_info;
3534
3535 const PixelPacket
3536 *pixels;
3537
3538 long
3539 id;
3540
3541 if (image->debug != MagickFalse)
3542 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3543 cache_info=(CacheInfo *) image->cache;
3544 id=GetOpenMPThreadId();
3545 assert(id < (long) cache_info->number_threads);
3546 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3547 cache_info->nexus_info[id],exception);
3548 return(pixels);
3549}
3550
3551/*
3552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3553% %
3554% %
3555% %
3556% G e t V i r t u a l P i x e l Q u e u e %
3557% %
3558% %
3559% %
3560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3561%
3562% GetVirtualPixelQueue() returns the virtual pixels associated with the
3563% last call to QueueAuthenticPixels() or GetVirtualPixels().
3564%
3565% The format of the GetVirtualPixelQueue() method is:
3566%
3567% const PixelPacket *GetVirtualPixelQueue(const Image image)
3568%
3569% A description of each parameter follows:
3570%
3571% o image: the image.
3572%
3573*/
3574MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3575{
3576 CacheInfo
3577 *cache_info;
3578
3579 assert(image != (const Image *) NULL);
3580 assert(image->signature == MagickSignature);
3581 if (image->debug != MagickFalse)
3582 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3583 assert(image->cache != (Cache) NULL);
3584 cache_info=(CacheInfo *) image->cache;
3585 assert(cache_info->signature == MagickSignature);
3586 if (cache_info->methods.get_virtual_pixels_handler ==
3587 (GetVirtualPixelsHandler) NULL)
3588 return((PixelPacket *) NULL);
3589 return(cache_info->methods.get_virtual_pixels_handler(image));
3590}
3591
3592/*
3593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3594% %
3595% %
3596% %
3597% G e t V i r t u a l P i x e l s %
3598% %
3599% %
3600% %
3601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3602%
3603% GetVirtualPixels() returns an immutable pixel region. If the
3604% region is successfully accessed, a pointer to it is returned, otherwise
3605% NULL is returned. The returned pointer may point to a temporary working
3606% copy of the pixels or it may point to the original pixels in memory.
3607% Performance is maximized if the selected region is part of one row, or one
3608% or more full rows, since there is opportunity to access the pixels in-place
3609% (without a copy) if the image is in RAM, or in a memory-mapped file. The
3610% returned pointer should *never* be deallocated by the user.
3611%
3612% Pixels accessed via the returned pointer represent a simple array of type
3613% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3614% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3615% the black color component or to obtain the colormap indexes (of type
3616% IndexPacket) corresponding to the region.
3617%
3618% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3619%
3620% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3621% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3622% GetCacheViewAuthenticPixels() instead.
3623%
3624% The format of the GetVirtualPixels() method is:
3625%
3626% const PixelPacket *GetVirtualPixels(const Image *image,const long x,
3627% const long y,const unsigned long columns,const unsigned long rows,
3628% ExceptionInfo *exception)
3629%
3630% A description of each parameter follows:
3631%
3632% o image: the image.
3633%
3634% o x,y,columns,rows: These values define the perimeter of a region of
3635% pixels.
3636%
3637% o exception: return any errors or warnings in this structure.
3638%
3639*/
3640MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3641 const long x,const long y,const unsigned long columns,
3642 const unsigned long rows,ExceptionInfo *exception)
3643{
3644 CacheInfo
3645 *cache_info;
3646
3647 const PixelPacket
3648 *pixels;
3649
3650 assert(image != (const Image *) NULL);
3651 assert(image->signature == MagickSignature);
3652 if (image->debug != MagickFalse)
3653 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3654 assert(image->cache != (Cache) NULL);
3655 cache_info=(CacheInfo *) image->cache;
3656 assert(cache_info->signature == MagickSignature);
3657 if (cache_info->methods.get_virtual_pixel_handler ==
3658 (GetVirtualPixelHandler) NULL)
3659 return((const PixelPacket *) NULL);
3660 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3661 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3662 return(pixels);
3663}
3664
3665/*
3666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3667% %
3668% %
3669% %
3670+ 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 %
3671% %
3672% %
3673% %
3674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3675%
3676% GetVirtualPixelsCache() returns the pixels associated with the last call
3677% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3678%
3679% The format of the GetVirtualPixelsCache() method is:
3680%
3681% PixelPacket *GetVirtualPixelsCache(const Image *image)
3682%
3683% A description of each parameter follows:
3684%
3685% o image: the image.
3686%
3687*/
3688static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3689{
3690 CacheInfo
3691 *cache_info;
3692
3693 const PixelPacket
3694 *pixels;
3695
3696 long
3697 id;
3698
3699 if (image->debug != MagickFalse)
3700 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3701 cache_info=(CacheInfo *) image->cache;
3702 id=GetOpenMPThreadId();
3703 assert(id < (long) cache_info->number_threads);
3704 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3705 return(pixels);
3706}
3707
3708/*
3709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3710% %
3711% %
3712% %
3713+ G e t V i r t u a l P i x e l s N e x u s %
3714% %
3715% %
3716% %
3717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3718%
3719% GetVirtualPixelsNexus() returns the pixels associated with the specified
3720% cache nexus.
3721%
3722% The format of the GetVirtualPixelsNexus() method is:
3723%
3724% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3725% NexusInfo *nexus_info)
3726%
3727% A description of each parameter follows:
3728%
3729% o cache: the pixel cache.
3730%
3731% o nexus_info: the cache nexus to return the colormap pixels.
3732%
3733*/
3734MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3735 NexusInfo *nexus_info)
3736{
3737 CacheInfo
3738 *cache_info;
3739
3740 if (cache == (Cache) NULL)
3741 return((PixelPacket *) NULL);
3742 cache_info=(CacheInfo *) cache;
3743 assert(cache_info->signature == MagickSignature);
3744 if (cache_info->storage_class == UndefinedClass)
3745 return((PixelPacket *) NULL);
3746 return((const PixelPacket *) nexus_info->pixels);
3747}
3748
3749/*
3750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3751% %
3752% %
3753% %
3754+ M a s k P i x e l C a c h e N e x u s %
3755% %
3756% %
3757% %
3758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3759%
3760% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3761% The method returns MagickTrue if the pixel region is masked, otherwise
3762% MagickFalse.
3763%
3764% The format of the MaskPixelCacheNexus() method is:
3765%
3766% MagickBooleanType MaskPixelCacheNexus(Image *image,
3767% NexusInfo *nexus_info,ExceptionInfo *exception)
3768%
3769% A description of each parameter follows:
3770%
3771% o image: the image.
3772%
3773% o nexus_info: the cache nexus to clip.
3774%
3775% o exception: return any errors or warnings in this structure.
3776%
3777*/
3778
3779static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3780 const MagickRealType alpha,const MagickPixelPacket *q,
3781 const MagickRealType beta,MagickPixelPacket *composite)
3782{
3783 MagickRealType
3784 gamma;
3785
3786 if (alpha == TransparentOpacity)
3787 {
3788 *composite=(*q);
3789 return;
3790 }
3791 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3792 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3793 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3794 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3795 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3796 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3797 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3798}
3799
3800static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3801 ExceptionInfo *exception)
3802{
3803 CacheInfo
3804 *cache_info;
3805
3806 MagickPixelPacket
3807 alpha,
3808 beta;
3809
3810 MagickSizeType
3811 number_pixels;
3812
3813 NexusInfo
3814 **clip_nexus,
3815 **image_nexus;
3816
3817 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003818 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003819
3820 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003821 *restrict nexus_indexes,
3822 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003823
3824 register long
3825 i;
3826
3827 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003828 *restrict p,
3829 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003830
3831 /*
3832 Apply clip mask.
3833 */
3834 if (image->debug != MagickFalse)
3835 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3836 if (image->mask == (Image *) NULL)
3837 return(MagickFalse);
3838 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3839 if (cache_info == (Cache) NULL)
3840 return(MagickFalse);
3841 image_nexus=AcquirePixelCacheNexus(1);
3842 clip_nexus=AcquirePixelCacheNexus(1);
3843 if ((image_nexus == (NexusInfo **) NULL) ||
3844 (clip_nexus == (NexusInfo **) NULL))
3845 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3846 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3847 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
3848 exception);
3849 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3850 q=nexus_info->pixels;
3851 nexus_indexes=nexus_info->indexes;
3852 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3853 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3854 nexus_info->region.height,clip_nexus[0],&image->exception);
3855 GetMagickPixelPacket(image,&alpha);
3856 GetMagickPixelPacket(image,&beta);
3857 number_pixels=(MagickSizeType) nexus_info->region.width*
3858 nexus_info->region.height;
3859 for (i=0; i < (long) number_pixels; i++)
3860 {
3861 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3862 break;
3863 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3864 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3865 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3866 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003867 q->red=ClampToQuantum(beta.red);
3868 q->green=ClampToQuantum(beta.green);
3869 q->blue=ClampToQuantum(beta.blue);
3870 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003871 if (cache_info->active_index_channel != MagickFalse)
3872 nexus_indexes[i]=indexes[i];
3873 p++;
3874 q++;
3875 r++;
3876 }
3877 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3878 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3879 if (i < (long) number_pixels)
3880 return(MagickFalse);
3881 return(MagickTrue);
3882}
3883
3884/*
3885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3886% %
3887% %
3888% %
3889+ O p e n P i x e l C a c h e %
3890% %
3891% %
3892% %
3893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3894%
3895% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3896% dimensions, allocating space for the image pixels and optionally the
3897% colormap indexes, and memory mapping the cache if it is disk based. The
3898% cache nexus array is initialized as well.
3899%
3900% The format of the OpenPixelCache() method is:
3901%
3902% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3903% ExceptionInfo *exception)
3904%
3905% A description of each parameter follows:
3906%
3907% o image: the image.
3908%
3909% o mode: ReadMode, WriteMode, or IOMode.
3910%
3911% o exception: return any errors or warnings in this structure.
3912%
3913*/
3914
3915static inline void AcquirePixelCachePixels(CacheInfo *cache_info)
3916{
3917 cache_info->mapped=MagickFalse;
3918 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3919 cache_info->length);
3920 if (cache_info->pixels == (PixelPacket *) NULL)
3921 {
3922 cache_info->mapped=MagickTrue;
3923 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3924 cache_info->length);
3925 }
3926}
3927
3928static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3929{
3930 CacheInfo
3931 *cache_info;
3932
3933 MagickOffsetType
3934 count,
3935 extent,
3936 offset;
3937
3938 cache_info=(CacheInfo *) image->cache;
3939 if (image->debug != MagickFalse)
3940 {
3941 char
3942 format[MaxTextExtent],
3943 message[MaxTextExtent];
3944
cristyb9080c92009-12-01 20:13:26 +00003945 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003946 (void) FormatMagickString(message,MaxTextExtent,
3947 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3948 cache_info->cache_filename,cache_info->file,format);
3949 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3950 }
3951 if (length != (MagickSizeType) ((MagickOffsetType) length))
3952 return(MagickFalse);
3953 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3954 if (extent < 0)
3955 return(MagickFalse);
3956 if ((MagickSizeType) extent >= length)
3957 return(MagickTrue);
3958 offset=(MagickOffsetType) length-1;
3959 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3960 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3961}
3962
3963static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3964 ExceptionInfo *exception)
3965{
3966 char
3967 format[MaxTextExtent],
3968 message[MaxTextExtent];
3969
3970 CacheInfo
3971 *cache_info,
3972 source_info;
3973
3974 MagickSizeType
3975 length,
3976 number_pixels;
3977
3978 MagickStatusType
3979 status;
3980
3981 size_t
3982 packet_size;
3983
3984 unsigned long
3985 columns;
3986
3987 if (image->debug != MagickFalse)
3988 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3989 if ((image->columns == 0) || (image->rows == 0))
3990 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3991 cache_info=(CacheInfo *) image->cache;
3992 source_info=(*cache_info);
3993 source_info.file=(-1);
3994 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
3995 image->filename,GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003996 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003997 cache_info->rows=image->rows;
3998 cache_info->columns=image->columns;
3999 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4000 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
4001 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4002 packet_size=sizeof(PixelPacket);
4003 if (cache_info->active_index_channel != MagickFalse)
4004 packet_size+=sizeof(IndexPacket);
4005 length=number_pixels*packet_size;
4006 columns=(unsigned long) (length/cache_info->rows/packet_size);
4007 if (cache_info->columns != columns)
4008 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4009 image->filename);
4010 cache_info->length=length;
4011 status=AcquireMagickResource(AreaResource,cache_info->length);
4012 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4013 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4014 {
4015 status=AcquireMagickResource(MemoryResource,cache_info->length);
4016 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4017 (cache_info->type == MemoryCache))
4018 {
4019 AcquirePixelCachePixels(cache_info);
4020 if (cache_info->pixels == (PixelPacket *) NULL)
4021 cache_info->pixels=source_info.pixels;
4022 else
4023 {
4024 /*
4025 Create memory pixel cache.
4026 */
4027 if (image->debug != MagickFalse)
4028 {
cristy97e7a572009-12-05 15:07:53 +00004029 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004030 format);
cristy3ed852e2009-09-05 21:47:34 +00004031 (void) FormatMagickString(message,MaxTextExtent,
4032 "open %s (%s memory, %lux%lu %s)",cache_info->filename,
4033 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4034 cache_info->columns,cache_info->rows,format);
4035 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4036 message);
4037 }
4038 cache_info->storage_class=image->storage_class;
4039 cache_info->colorspace=image->colorspace;
4040 cache_info->type=MemoryCache;
4041 cache_info->indexes=(IndexPacket *) NULL;
4042 if (cache_info->active_index_channel != MagickFalse)
4043 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4044 number_pixels);
4045 if (source_info.storage_class != UndefinedClass)
4046 {
4047 status|=ClonePixelCachePixels(cache_info,&source_info,
4048 exception);
4049 RelinquishPixelCachePixels(&source_info);
4050 }
4051 return(MagickTrue);
4052 }
4053 }
4054 RelinquishMagickResource(MemoryResource,cache_info->length);
4055 }
4056 /*
4057 Create pixel cache on disk.
4058 */
4059 status=AcquireMagickResource(DiskResource,cache_info->length);
4060 if (status == MagickFalse)
4061 {
4062 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4063 "CacheResourcesExhausted","`%s'",image->filename);
4064 return(MagickFalse);
4065 }
4066 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4067 {
4068 RelinquishMagickResource(DiskResource,cache_info->length);
4069 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4070 image->filename);
4071 return(MagickFalse);
4072 }
4073 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4074 cache_info->length);
4075 if (status == MagickFalse)
4076 {
4077 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4078 image->filename);
4079 return(MagickFalse);
4080 }
4081 cache_info->storage_class=image->storage_class;
4082 cache_info->colorspace=image->colorspace;
4083 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4084 status=AcquireMagickResource(AreaResource,cache_info->length);
4085 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4086 cache_info->type=DiskCache;
4087 else
4088 {
4089 status=AcquireMagickResource(MapResource,cache_info->length);
4090 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4091 (cache_info->type != MemoryCache))
4092 cache_info->type=DiskCache;
4093 else
4094 {
4095 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4096 cache_info->offset,(size_t) cache_info->length);
4097 if (cache_info->pixels == (PixelPacket *) NULL)
4098 {
4099 cache_info->pixels=source_info.pixels;
4100 cache_info->type=DiskCache;
4101 }
4102 else
4103 {
4104 /*
4105 Create file-backed memory-mapped pixel cache.
4106 */
4107 (void) ClosePixelCacheOnDisk(cache_info);
4108 cache_info->type=MapCache;
4109 cache_info->mapped=MagickTrue;
4110 cache_info->indexes=(IndexPacket *) NULL;
4111 if (cache_info->active_index_channel != MagickFalse)
4112 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4113 number_pixels);
4114 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4115 {
4116 status=ClonePixelCachePixels(cache_info,&source_info,
4117 exception);
4118 RelinquishPixelCachePixels(&source_info);
4119 }
4120 if (image->debug != MagickFalse)
4121 {
cristy97e7a572009-12-05 15:07:53 +00004122 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004123 format);
cristy3ed852e2009-09-05 21:47:34 +00004124 (void) FormatMagickString(message,MaxTextExtent,
4125 "open %s (%s[%d], memory-mapped, %lux%lu %s)",
4126 cache_info->filename,cache_info->cache_filename,
4127 cache_info->file,cache_info->columns,cache_info->rows,
4128 format);
4129 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4130 message);
4131 }
4132 return(MagickTrue);
4133 }
4134 }
4135 RelinquishMagickResource(MapResource,cache_info->length);
4136 }
4137 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4138 {
4139 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4140 RelinquishPixelCachePixels(&source_info);
4141 }
4142 if (image->debug != MagickFalse)
4143 {
cristyb9080c92009-12-01 20:13:26 +00004144 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004145 (void) FormatMagickString(message,MaxTextExtent,
4146 "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
4147 cache_info->cache_filename,cache_info->file,cache_info->columns,
4148 cache_info->rows,format);
4149 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4150 }
4151 return(MagickTrue);
4152}
4153
4154/*
4155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4156% %
4157% %
4158% %
4159+ P e r s i s t P i x e l C a c h e %
4160% %
4161% %
4162% %
4163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4164%
4165% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4166% persistent pixel cache is one that resides on disk and is not destroyed
4167% when the program exits.
4168%
4169% The format of the PersistPixelCache() method is:
4170%
4171% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4172% const MagickBooleanType attach,MagickOffsetType *offset,
4173% ExceptionInfo *exception)
4174%
4175% A description of each parameter follows:
4176%
4177% o image: the image.
4178%
4179% o filename: the persistent pixel cache filename.
4180%
cristy01b7eb02009-09-10 23:10:14 +00004181% o attach: A value other than zero initializes the persistent pixel
4182% cache.
4183%
cristy3ed852e2009-09-05 21:47:34 +00004184% o initialize: A value other than zero initializes the persistent pixel
4185% cache.
4186%
4187% o offset: the offset in the persistent cache to store pixels.
4188%
4189% o exception: return any errors or warnings in this structure.
4190%
4191*/
4192MagickExport MagickBooleanType PersistPixelCache(Image *image,
4193 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4194 ExceptionInfo *exception)
4195{
4196 CacheInfo
4197 *cache_info,
4198 *clone_info;
4199
4200 Image
4201 clone_image;
4202
4203 long
cristy688f07b2009-09-27 15:19:13 +00004204 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004205
4206 MagickBooleanType
4207 status;
4208
4209 assert(image != (Image *) NULL);
4210 assert(image->signature == MagickSignature);
4211 if (image->debug != MagickFalse)
4212 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4213 assert(image->cache != (void *) NULL);
4214 assert(filename != (const char *) NULL);
4215 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004216 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004217 cache_info=(CacheInfo *) image->cache;
4218 assert(cache_info->signature == MagickSignature);
4219 if (attach != MagickFalse)
4220 {
4221 /*
cristy01b7eb02009-09-10 23:10:14 +00004222 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004223 */
4224 if (image->debug != MagickFalse)
4225 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4226 "attach persistent cache");
4227 (void) CopyMagickString(cache_info->cache_filename,filename,
4228 MaxTextExtent);
4229 cache_info->type=DiskCache;
4230 cache_info->offset=(*offset);
4231 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4232 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004233 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004234 return(MagickTrue);
4235 }
cristy01b7eb02009-09-10 23:10:14 +00004236 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4237 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004238 {
cristyf84a1932010-01-03 18:00:18 +00004239 LockSemaphoreInfo(cache_info->semaphore);
cristy01b7eb02009-09-10 23:10:14 +00004240 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004241 (cache_info->reference_count == 1))
4242 {
4243 int
4244 status;
4245
4246 /*
cristy01b7eb02009-09-10 23:10:14 +00004247 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004248 */
4249 status=rename(cache_info->cache_filename,filename);
4250 if (status == 0)
4251 {
4252 (void) CopyMagickString(cache_info->cache_filename,filename,
4253 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004254 *offset+=cache_info->length+page_size-(cache_info->length %
4255 page_size);
cristyf84a1932010-01-03 18:00:18 +00004256 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004257 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004258 if (image->debug != MagickFalse)
4259 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4260 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004261 return(MagickTrue);
4262 }
4263 }
cristyf84a1932010-01-03 18:00:18 +00004264 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004265 }
4266 /*
cristy01b7eb02009-09-10 23:10:14 +00004267 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004268 */
4269 clone_image=(*image);
4270 clone_info=(CacheInfo *) clone_image.cache;
4271 image->cache=ClonePixelCache(cache_info);
4272 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4273 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4274 cache_info->type=DiskCache;
4275 cache_info->offset=(*offset);
4276 cache_info=(CacheInfo *) image->cache;
4277 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4278 if (status != MagickFalse)
4279 {
4280 status=OpenPixelCache(image,IOMode,exception);
4281 if (status != MagickFalse)
4282 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4283 }
cristy688f07b2009-09-27 15:19:13 +00004284 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004285 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4286 return(status);
4287}
4288
4289/*
4290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4291% %
4292% %
4293% %
4294+ Q u e u e A u t h e n t i c N e x u s %
4295% %
4296% %
4297% %
4298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4299%
4300% QueueAuthenticNexus() allocates an region to store image pixels as defined
4301% by the region rectangle and returns a pointer to the region. This region is
4302% subsequently transferred from the pixel cache with
4303% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4304% pixels are transferred, otherwise a NULL is returned.
4305%
4306% The format of the QueueAuthenticNexus() method is:
4307%
4308% PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
4309% const unsigned long columns,const unsigned long rows,
4310% NexusInfo *nexus_info,ExceptionInfo *exception)
4311%
4312% A description of each parameter follows:
4313%
4314% o image: the image.
4315%
4316% o x,y,columns,rows: These values define the perimeter of a region of
4317% pixels.
4318%
4319% o nexus_info: the cache nexus to set.
4320%
4321% o exception: return any errors or warnings in this structure.
4322%
4323*/
4324MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
4325 const long y,const unsigned long columns,const unsigned long rows,
4326 NexusInfo *nexus_info,ExceptionInfo *exception)
4327{
4328 CacheInfo
4329 *cache_info;
4330
4331 MagickOffsetType
4332 offset;
4333
4334 MagickSizeType
4335 number_pixels;
4336
4337 RectangleInfo
4338 region;
4339
4340 /*
4341 Validate pixel cache geometry.
4342 */
4343 cache_info=(CacheInfo *) image->cache;
4344 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4345 {
4346 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4347 "NoPixelsDefinedInCache","`%s'",image->filename);
4348 return((PixelPacket *) NULL);
4349 }
4350 if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
4351 (y >= (long) cache_info->rows))
4352 {
4353 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4354 "PixelsAreNotAuthentic","`%s'",image->filename);
4355 return((PixelPacket *) NULL);
4356 }
4357 offset=(MagickOffsetType) y*cache_info->columns+x;
4358 if (offset < 0)
4359 return((PixelPacket *) NULL);
4360 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4361 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4362 if ((MagickSizeType) offset >= number_pixels)
4363 return((PixelPacket *) NULL);
4364 /*
4365 Return pixel cache.
4366 */
4367 region.x=x;
4368 region.y=y;
4369 region.width=columns;
4370 region.height=rows;
4371 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4372}
4373
4374/*
4375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4376% %
4377% %
4378% %
4379+ 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 %
4380% %
4381% %
4382% %
4383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4384%
4385% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4386% defined by the region rectangle and returns a pointer to the region. This
4387% region is subsequently transferred from the pixel cache with
4388% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4389% pixels are transferred, otherwise a NULL is returned.
4390%
4391% The format of the QueueAuthenticPixelsCache() method is:
4392%
4393% PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4394% const long y,const unsigned long columns,const unsigned long rows,
4395% ExceptionInfo *exception)
4396%
4397% A description of each parameter follows:
4398%
4399% o image: the image.
4400%
4401% o x,y,columns,rows: These values define the perimeter of a region of
4402% pixels.
4403%
4404% o exception: return any errors or warnings in this structure.
4405%
4406*/
4407static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4408 const long y,const unsigned long columns,const unsigned long rows,
4409 ExceptionInfo *exception)
4410{
4411 CacheInfo
4412 *cache_info;
4413
4414 long
4415 id;
4416
4417 PixelPacket
4418 *pixels;
4419
4420 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4421 if (cache_info == (Cache) NULL)
4422 return((PixelPacket *) NULL);
4423 id=GetOpenMPThreadId();
4424 assert(id < (long) cache_info->number_threads);
4425 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4426 exception);
4427 return(pixels);
4428}
4429
4430/*
4431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4432% %
4433% %
4434% %
4435% Q u e u e A u t h e n t i c P i x e l s %
4436% %
4437% %
4438% %
4439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4440%
4441% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4442% successfully intialized a pointer to a PixelPacket array representing the
4443% region is returned, otherwise NULL is returned. The returned pointer may
4444% point to a temporary working buffer for the pixels or it may point to the
4445% final location of the pixels in memory.
4446%
4447% Write-only access means that any existing pixel values corresponding to
4448% the region are ignored. This is useful if the initial image is being
4449% created from scratch, or if the existing pixel values are to be
4450% completely replaced without need to refer to their pre-existing values.
4451% The application is free to read and write the pixel buffer returned by
4452% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4453% initialize the pixel array values. Initializing pixel array values is the
4454% application's responsibility.
4455%
4456% Performance is maximized if the selected region is part of one row, or
4457% one or more full rows, since then there is opportunity to access the
4458% pixels in-place (without a copy) if the image is in RAM, or in a
4459% memory-mapped file. The returned pointer should *never* be deallocated
4460% by the user.
4461%
4462% Pixels accessed via the returned pointer represent a simple array of type
4463% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4464% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4465% the black color component or the colormap indexes (of type IndexPacket)
4466% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4467% array has been updated, the changes must be saved back to the underlying
4468% image using SyncAuthenticPixels() or they may be lost.
4469%
4470% The format of the QueueAuthenticPixels() method is:
4471%
4472% PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
4473% const unsigned long columns,const unsigned long rows,
4474% ExceptionInfo *exception)
4475%
4476% A description of each parameter follows:
4477%
4478% o image: the image.
4479%
4480% o x,y,columns,rows: These values define the perimeter of a region of
4481% pixels.
4482%
4483% o exception: return any errors or warnings in this structure.
4484%
4485*/
4486MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
4487 const long y,const unsigned long columns,const unsigned long rows,
4488 ExceptionInfo *exception)
4489{
4490 CacheInfo
4491 *cache_info;
4492
4493 PixelPacket
4494 *pixels;
4495
4496 assert(image != (Image *) NULL);
4497 assert(image->signature == MagickSignature);
4498 if (image->debug != MagickFalse)
4499 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4500 assert(image->cache != (Cache) NULL);
4501 cache_info=(CacheInfo *) image->cache;
4502 assert(cache_info->signature == MagickSignature);
4503 if (cache_info->methods.queue_authentic_pixels_handler ==
4504 (QueueAuthenticPixelsHandler) NULL)
4505 return((PixelPacket *) NULL);
4506 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4507 rows,exception);
4508 return(pixels);
4509}
4510
4511/*
4512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4513% %
4514% %
4515% %
4516+ R e a d P i x e l C a c h e I n d e x e s %
4517% %
4518% %
4519% %
4520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4521%
4522% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4523% the pixel cache.
4524%
4525% The format of the ReadPixelCacheIndexes() method is:
4526%
4527% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4528% NexusInfo *nexus_info,ExceptionInfo *exception)
4529%
4530% A description of each parameter follows:
4531%
4532% o cache_info: the pixel cache.
4533%
4534% o nexus_info: the cache nexus to read the colormap indexes.
4535%
4536% o exception: return any errors or warnings in this structure.
4537%
4538*/
4539static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4540 NexusInfo *nexus_info,ExceptionInfo *exception)
4541{
4542 MagickOffsetType
4543 count,
4544 offset;
4545
4546 MagickSizeType
4547 length,
4548 number_pixels;
4549
4550 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004551 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004552
4553 register long
4554 y;
4555
4556 unsigned long
4557 rows;
4558
4559 if (cache_info->debug != MagickFalse)
4560 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4561 cache_info->filename);
4562 if (cache_info->active_index_channel == MagickFalse)
4563 return(MagickFalse);
4564 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4565 return(MagickTrue);
4566 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4567 nexus_info->region.x;
4568 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4569 rows=nexus_info->region.height;
4570 number_pixels=length*rows;
4571 if ((cache_info->columns == nexus_info->region.width) &&
4572 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4573 {
4574 length=number_pixels;
4575 rows=1UL;
4576 }
4577 q=nexus_info->indexes;
4578 switch (cache_info->type)
4579 {
4580 case MemoryCache:
4581 case MapCache:
4582 {
4583 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004584 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004585
4586 /*
4587 Read indexes from memory.
4588 */
4589 p=cache_info->indexes+offset;
4590 for (y=0; y < (long) rows; y++)
4591 {
4592 (void) CopyMagickMemory(q,p,(size_t) length);
4593 p+=cache_info->columns;
4594 q+=nexus_info->region.width;
4595 }
4596 break;
4597 }
4598 case DiskCache:
4599 {
4600 /*
4601 Read indexes from disk.
4602 */
4603 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4604 {
4605 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4606 cache_info->cache_filename);
4607 return(MagickFalse);
4608 }
4609 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4610 for (y=0; y < (long) rows; y++)
4611 {
4612 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4613 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4614 if ((MagickSizeType) count < length)
4615 break;
4616 offset+=cache_info->columns;
4617 q+=nexus_info->region.width;
4618 }
4619 if (y < (long) rows)
4620 {
4621 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4622 cache_info->cache_filename);
4623 return(MagickFalse);
4624 }
4625 break;
4626 }
4627 default:
4628 break;
4629 }
4630 if ((cache_info->debug != MagickFalse) &&
4631 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4632 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4633 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4634 nexus_info->region.x,nexus_info->region.y);
4635 return(MagickTrue);
4636}
4637
4638/*
4639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4640% %
4641% %
4642% %
4643+ R e a d P i x e l C a c h e P i x e l s %
4644% %
4645% %
4646% %
4647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4648%
4649% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4650% cache.
4651%
4652% The format of the ReadPixelCachePixels() method is:
4653%
4654% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4655% NexusInfo *nexus_info,ExceptionInfo *exception)
4656%
4657% A description of each parameter follows:
4658%
4659% o cache_info: the pixel cache.
4660%
4661% o nexus_info: the cache nexus to read the pixels.
4662%
4663% o exception: return any errors or warnings in this structure.
4664%
4665*/
4666static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4667 NexusInfo *nexus_info,ExceptionInfo *exception)
4668{
4669 MagickOffsetType
4670 count,
4671 offset;
4672
4673 MagickSizeType
4674 length,
4675 number_pixels;
4676
4677 register long
4678 y;
4679
4680 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004681 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004682
4683 unsigned long
4684 rows;
4685
4686 if (cache_info->debug != MagickFalse)
4687 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4688 cache_info->filename);
4689 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4690 return(MagickTrue);
4691 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4692 nexus_info->region.x;
4693 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4694 rows=nexus_info->region.height;
4695 number_pixels=length*rows;
4696 if ((cache_info->columns == nexus_info->region.width) &&
4697 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4698 {
4699 length=number_pixels;
4700 rows=1UL;
4701 }
4702 q=nexus_info->pixels;
4703 switch (cache_info->type)
4704 {
4705 case MemoryCache:
4706 case MapCache:
4707 {
4708 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004709 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004710
4711 /*
4712 Read pixels from memory.
4713 */
4714 p=cache_info->pixels+offset;
4715 for (y=0; y < (long) rows; y++)
4716 {
4717 (void) CopyMagickMemory(q,p,(size_t) length);
4718 p+=cache_info->columns;
4719 q+=nexus_info->region.width;
4720 }
4721 break;
4722 }
4723 case DiskCache:
4724 {
4725 /*
4726 Read pixels from disk.
4727 */
4728 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4729 {
4730 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4731 cache_info->cache_filename);
4732 return(MagickFalse);
4733 }
4734 for (y=0; y < (long) rows; y++)
4735 {
4736 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4737 sizeof(*q),length,(unsigned char *) q);
4738 if ((MagickSizeType) count < length)
4739 break;
4740 offset+=cache_info->columns;
4741 q+=nexus_info->region.width;
4742 }
4743 if (y < (long) rows)
4744 {
4745 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4746 cache_info->cache_filename);
4747 return(MagickFalse);
4748 }
4749 break;
4750 }
4751 default:
4752 break;
4753 }
4754 if ((cache_info->debug != MagickFalse) &&
4755 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4756 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4757 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4758 nexus_info->region.x,nexus_info->region.y);
4759 return(MagickTrue);
4760}
4761
4762/*
4763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4764% %
4765% %
4766% %
4767+ R e f e r e n c e P i x e l C a c h e %
4768% %
4769% %
4770% %
4771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4772%
4773% ReferencePixelCache() increments the reference count associated with the
4774% pixel cache returning a pointer to the cache.
4775%
4776% The format of the ReferencePixelCache method is:
4777%
4778% Cache ReferencePixelCache(Cache cache_info)
4779%
4780% A description of each parameter follows:
4781%
4782% o cache_info: the pixel cache.
4783%
4784*/
4785MagickExport Cache ReferencePixelCache(Cache cache)
4786{
4787 CacheInfo
4788 *cache_info;
4789
4790 assert(cache != (Cache *) NULL);
4791 cache_info=(CacheInfo *) cache;
4792 assert(cache_info->signature == MagickSignature);
4793 if (cache_info->debug != MagickFalse)
4794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4795 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004796 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004797 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004798 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004799 return(cache_info);
4800}
4801
4802/*
4803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4804% %
4805% %
4806% %
4807+ S e t P i x e l C a c h e M e t h o d s %
4808% %
4809% %
4810% %
4811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4812%
4813% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4814%
4815% The format of the SetPixelCacheMethods() method is:
4816%
4817% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4818%
4819% A description of each parameter follows:
4820%
4821% o cache: the pixel cache.
4822%
4823% o cache_methods: Specifies a pointer to a CacheMethods structure.
4824%
4825*/
4826MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4827{
4828 CacheInfo
4829 *cache_info;
4830
4831 GetOneAuthenticPixelFromHandler
4832 get_one_authentic_pixel_from_handler;
4833
4834 GetOneVirtualPixelFromHandler
4835 get_one_virtual_pixel_from_handler;
4836
4837 /*
4838 Set cache pixel methods.
4839 */
4840 assert(cache != (Cache) NULL);
4841 assert(cache_methods != (CacheMethods *) NULL);
4842 cache_info=(CacheInfo *) cache;
4843 assert(cache_info->signature == MagickSignature);
4844 if (cache_info->debug != MagickFalse)
4845 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4846 cache_info->filename);
4847 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4848 cache_info->methods.get_virtual_pixel_handler=
4849 cache_methods->get_virtual_pixel_handler;
4850 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4851 cache_info->methods.destroy_pixel_handler=
4852 cache_methods->destroy_pixel_handler;
4853 if (cache_methods->get_virtual_indexes_from_handler !=
4854 (GetVirtualIndexesFromHandler) NULL)
4855 cache_info->methods.get_virtual_indexes_from_handler=
4856 cache_methods->get_virtual_indexes_from_handler;
4857 if (cache_methods->get_authentic_pixels_handler !=
4858 (GetAuthenticPixelsHandler) NULL)
4859 cache_info->methods.get_authentic_pixels_handler=
4860 cache_methods->get_authentic_pixels_handler;
4861 if (cache_methods->queue_authentic_pixels_handler !=
4862 (QueueAuthenticPixelsHandler) NULL)
4863 cache_info->methods.queue_authentic_pixels_handler=
4864 cache_methods->queue_authentic_pixels_handler;
4865 if (cache_methods->sync_authentic_pixels_handler !=
4866 (SyncAuthenticPixelsHandler) NULL)
4867 cache_info->methods.sync_authentic_pixels_handler=
4868 cache_methods->sync_authentic_pixels_handler;
4869 if (cache_methods->get_authentic_pixels_from_handler !=
4870 (GetAuthenticPixelsFromHandler) NULL)
4871 cache_info->methods.get_authentic_pixels_from_handler=
4872 cache_methods->get_authentic_pixels_from_handler;
4873 if (cache_methods->get_authentic_indexes_from_handler !=
4874 (GetAuthenticIndexesFromHandler) NULL)
4875 cache_info->methods.get_authentic_indexes_from_handler=
4876 cache_methods->get_authentic_indexes_from_handler;
4877 get_one_virtual_pixel_from_handler=
4878 cache_info->methods.get_one_virtual_pixel_from_handler;
4879 if (get_one_virtual_pixel_from_handler !=
4880 (GetOneVirtualPixelFromHandler) NULL)
4881 cache_info->methods.get_one_virtual_pixel_from_handler=
4882 cache_methods->get_one_virtual_pixel_from_handler;
4883 get_one_authentic_pixel_from_handler=
4884 cache_methods->get_one_authentic_pixel_from_handler;
4885 if (get_one_authentic_pixel_from_handler !=
4886 (GetOneAuthenticPixelFromHandler) NULL)
4887 cache_info->methods.get_one_authentic_pixel_from_handler=
4888 cache_methods->get_one_authentic_pixel_from_handler;
4889}
4890
4891/*
4892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4893% %
4894% %
4895% %
4896+ S e t P i x e l C a c h e N e x u s P i x e l s %
4897% %
4898% %
4899% %
4900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4901%
4902% SetPixelCacheNexusPixels() defines the region of the cache for the
4903% specified cache nexus.
4904%
4905% The format of the SetPixelCacheNexusPixels() method is:
4906%
4907% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4908% const RectangleInfo *region,NexusInfo *nexus_info,
4909% ExceptionInfo *exception)
4910%
4911% A description of each parameter follows:
4912%
4913% o image: the image.
4914%
4915% o region: A pointer to the RectangleInfo structure that defines the
4916% region of this particular cache nexus.
4917%
4918% o nexus_info: the cache nexus to set.
4919%
4920% o exception: return any errors or warnings in this structure.
4921%
4922*/
4923static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4924 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4925{
4926 CacheInfo
4927 *cache_info;
4928
4929 MagickBooleanType
4930 status;
4931
4932 MagickOffsetType
4933 offset;
4934
4935 MagickSizeType
4936 length,
4937 number_pixels;
4938
4939 if (image->debug != MagickFalse)
4940 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4941 cache_info=(CacheInfo *) image->cache;
4942 assert(cache_info->signature == MagickSignature);
4943 if (cache_info->type == UndefinedCache)
4944 return((PixelPacket *) NULL);
4945 nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
4946 nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
4947 nexus_info->region.x=region->x;
4948 nexus_info->region.y=region->y;
4949 if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
4950 (image->mask == (Image *) NULL))
4951 {
4952 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4953 nexus_info->region.x;
4954 length=(MagickSizeType) (nexus_info->region.height-1)*cache_info->columns+
4955 nexus_info->region.width-1;
4956 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4957 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
4958 {
4959 long
4960 x,
4961 y;
4962
4963 x=nexus_info->region.x+nexus_info->region.width;
4964 y=nexus_info->region.y+nexus_info->region.height;
4965 if ((nexus_info->region.x >= 0) &&
4966 (x <= (long) cache_info->columns) &&
4967 (nexus_info->region.y >= 0) && (y <= (long) cache_info->rows))
4968 if ((nexus_info->region.height == 1UL) ||
4969 ((nexus_info->region.x == 0) &&
4970 ((nexus_info->region.width % cache_info->columns) == 0)))
4971 {
4972 /*
4973 Pixels are accessed directly from memory.
4974 */
4975 nexus_info->pixels=cache_info->pixels+offset;
4976 nexus_info->indexes=(IndexPacket *) NULL;
4977 if (cache_info->active_index_channel != MagickFalse)
4978 nexus_info->indexes=cache_info->indexes+offset;
4979 return(nexus_info->pixels);
4980 }
4981 }
4982 }
4983 /*
4984 Pixels are stored in a cache region until they are synced to the cache.
4985 */
4986 number_pixels=(MagickSizeType) nexus_info->region.width*
4987 nexus_info->region.height;
4988 length=number_pixels*sizeof(PixelPacket);
4989 if (cache_info->active_index_channel != MagickFalse)
4990 length+=number_pixels*sizeof(IndexPacket);
4991 if (nexus_info->cache == (PixelPacket *) NULL)
4992 {
4993 nexus_info->length=length;
4994 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4995 if (status == MagickFalse)
4996 return((PixelPacket *) NULL);
4997 }
4998 else
4999 if (nexus_info->length != length)
5000 {
5001 RelinquishCacheNexusPixels(nexus_info);
5002 nexus_info->length=length;
5003 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5004 if (status == MagickFalse)
5005 return((PixelPacket *) NULL);
5006 }
5007 nexus_info->pixels=nexus_info->cache;
5008 nexus_info->indexes=(IndexPacket *) NULL;
5009 if (cache_info->active_index_channel != MagickFalse)
5010 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5011 return(nexus_info->pixels);
5012}
5013
5014/*
5015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5016% %
5017% %
5018% %
5019% 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 %
5020% %
5021% %
5022% %
5023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5024%
5025% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5026% pixel cache and returns the previous setting. A virtual pixel is any pixel
5027% access that is outside the boundaries of the image cache.
5028%
5029% The format of the SetPixelCacheVirtualMethod() method is:
5030%
5031% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5032% const VirtualPixelMethod virtual_pixel_method)
5033%
5034% A description of each parameter follows:
5035%
5036% o image: the image.
5037%
5038% o virtual_pixel_method: choose the type of virtual pixel.
5039%
5040*/
5041MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5042 const VirtualPixelMethod virtual_pixel_method)
5043{
5044 CacheInfo
5045 *cache_info;
5046
5047 VirtualPixelMethod
5048 method;
5049
5050 assert(image != (Image *) NULL);
5051 assert(image->signature == MagickSignature);
5052 if (image->debug != MagickFalse)
5053 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5054 assert(image->cache != (Cache) NULL);
5055 cache_info=(CacheInfo *) image->cache;
5056 assert(cache_info->signature == MagickSignature);
5057 method=cache_info->virtual_pixel_method;
5058 cache_info->virtual_pixel_method=virtual_pixel_method;
5059 return(method);
5060}
5061
5062/*
5063%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5064% %
5065% %
5066% %
5067+ 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 %
5068% %
5069% %
5070% %
5071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5072%
5073% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5074% in-memory or disk cache. The method returns MagickTrue if the pixel region
5075% is synced, otherwise MagickFalse.
5076%
5077% The format of the SyncAuthenticPixelCacheNexus() method is:
5078%
5079% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5080% NexusInfo *nexus_info,ExceptionInfo *exception)
5081%
5082% A description of each parameter follows:
5083%
5084% o image: the image.
5085%
5086% o nexus_info: the cache nexus to sync.
5087%
5088% o exception: return any errors or warnings in this structure.
5089%
5090*/
5091MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5092 NexusInfo *nexus_info,ExceptionInfo *exception)
5093{
5094 CacheInfo
5095 *cache_info;
5096
5097 MagickBooleanType
5098 status;
5099
5100 /*
5101 Transfer pixels to the cache.
5102 */
5103 assert(image != (Image *) NULL);
5104 assert(image->signature == MagickSignature);
5105 if (image->debug != MagickFalse)
5106 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5107 if (image->cache == (Cache) NULL)
5108 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5109 cache_info=(CacheInfo *) image->cache;
5110 if (cache_info->type == UndefinedCache)
5111 return(MagickFalse);
5112 if ((image->clip_mask != (Image *) NULL) &&
5113 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5114 return(MagickFalse);
5115 if ((image->mask != (Image *) NULL) &&
5116 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5117 return(MagickFalse);
5118 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5119 return(MagickTrue);
5120 assert(cache_info->signature == MagickSignature);
5121 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5122 if ((cache_info->active_index_channel != MagickFalse) &&
5123 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5124 return(MagickFalse);
5125 return(status);
5126}
5127
5128/*
5129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5130% %
5131% %
5132% %
5133+ S y n c A u t h e n t i c P i x e l C a c h e %
5134% %
5135% %
5136% %
5137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5138%
5139% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5140% or disk cache. The method returns MagickTrue if the pixel region is synced,
5141% otherwise MagickFalse.
5142%
5143% The format of the SyncAuthenticPixelsCache() method is:
5144%
5145% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5146% ExceptionInfo *exception)
5147%
5148% A description of each parameter follows:
5149%
5150% o image: the image.
5151%
5152% o exception: return any errors or warnings in this structure.
5153%
5154*/
5155static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5156 ExceptionInfo *exception)
5157{
5158 CacheInfo
5159 *cache_info;
5160
5161 long
5162 id;
5163
5164 MagickBooleanType
5165 status;
5166
5167 cache_info=(CacheInfo *) image->cache;
5168 id=GetOpenMPThreadId();
5169 assert(id < (long) cache_info->number_threads);
5170 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5171 exception);
5172 return(status);
5173}
5174
5175/*
5176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5177% %
5178% %
5179% %
5180% S y n c A u t h e n t i c P i x e l s %
5181% %
5182% %
5183% %
5184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5185%
5186% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5187% The method returns MagickTrue if the pixel region is flushed, otherwise
5188% MagickFalse.
5189%
5190% The format of the SyncAuthenticPixels() method is:
5191%
5192% MagickBooleanType SyncAuthenticPixels(Image *image,
5193% ExceptionInfo *exception)
5194%
5195% A description of each parameter follows:
5196%
5197% o image: the image.
5198%
5199% o exception: return any errors or warnings in this structure.
5200%
5201*/
5202MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5203 ExceptionInfo *exception)
5204{
5205 CacheInfo
5206 *cache_info;
5207
5208 assert(image != (Image *) NULL);
5209 assert(image->signature == MagickSignature);
5210 if (image->debug != MagickFalse)
5211 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5212 assert(image->cache != (Cache) NULL);
5213 cache_info=(CacheInfo *) image->cache;
5214 assert(cache_info->signature == MagickSignature);
5215 if (cache_info->methods.sync_authentic_pixels_handler ==
5216 (SyncAuthenticPixelsHandler) NULL)
5217 return(MagickFalse);
5218 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5219}
5220
5221/*
5222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5223% %
5224% %
5225% %
5226+ W r i t e P i x e l C a c h e I n d e x e s %
5227% %
5228% %
5229% %
5230%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5231%
5232% WritePixelCacheIndexes() writes the colormap indexes to the specified
5233% region of the pixel cache.
5234%
5235% The format of the WritePixelCacheIndexes() method is:
5236%
5237% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5238% NexusInfo *nexus_info,ExceptionInfo *exception)
5239%
5240% A description of each parameter follows:
5241%
5242% o cache_info: the pixel cache.
5243%
5244% o nexus_info: the cache nexus to write the colormap indexes.
5245%
5246% o exception: return any errors or warnings in this structure.
5247%
5248*/
5249static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5250 NexusInfo *nexus_info,ExceptionInfo *exception)
5251{
5252 MagickOffsetType
5253 count,
5254 offset;
5255
5256 MagickSizeType
5257 length,
5258 number_pixels;
5259
5260 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005261 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005262
5263 register long
5264 y;
5265
5266 unsigned long
5267 rows;
5268
5269 if (cache_info->debug != MagickFalse)
5270 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5271 cache_info->filename);
5272 if (cache_info->active_index_channel == MagickFalse)
5273 return(MagickFalse);
5274 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5275 return(MagickTrue);
5276 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5277 nexus_info->region.x;
5278 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5279 rows=nexus_info->region.height;
5280 number_pixels=(MagickSizeType) length*rows;
5281 if ((cache_info->columns == nexus_info->region.width) &&
5282 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5283 {
5284 length=number_pixels;
5285 rows=1UL;
5286 }
5287 p=nexus_info->indexes;
5288 switch (cache_info->type)
5289 {
5290 case MemoryCache:
5291 case MapCache:
5292 {
5293 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005294 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005295
5296 /*
5297 Write indexes to memory.
5298 */
5299 q=cache_info->indexes+offset;
5300 for (y=0; y < (long) rows; y++)
5301 {
5302 (void) CopyMagickMemory(q,p,(size_t) length);
5303 p+=nexus_info->region.width;
5304 q+=cache_info->columns;
5305 }
5306 break;
5307 }
5308 case DiskCache:
5309 {
5310 /*
5311 Write indexes to disk.
5312 */
5313 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5314 {
5315 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5316 cache_info->cache_filename);
5317 return(MagickFalse);
5318 }
5319 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5320 for (y=0; y < (long) rows; y++)
5321 {
5322 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5323 sizeof(PixelPacket)+offset*sizeof(*p),length,
5324 (const unsigned char *) p);
5325 if ((MagickSizeType) count < length)
5326 break;
5327 p+=nexus_info->region.width;
5328 offset+=cache_info->columns;
5329 }
5330 if (y < (long) rows)
5331 {
5332 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5333 cache_info->cache_filename);
5334 return(MagickFalse);
5335 }
5336 break;
5337 }
5338 default:
5339 break;
5340 }
5341 if ((cache_info->debug != MagickFalse) &&
5342 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5343 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5344 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5345 nexus_info->region.x,nexus_info->region.y);
5346 return(MagickTrue);
5347}
5348
5349/*
5350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5351% %
5352% %
5353% %
5354+ W r i t e C a c h e P i x e l s %
5355% %
5356% %
5357% %
5358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5359%
5360% WritePixelCachePixels() writes image pixels to the specified region of the
5361% pixel cache.
5362%
5363% The format of the WritePixelCachePixels() method is:
5364%
5365% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5366% NexusInfo *nexus_info,ExceptionInfo *exception)
5367%
5368% A description of each parameter follows:
5369%
5370% o cache_info: the pixel cache.
5371%
5372% o nexus_info: the cache nexus to write the pixels.
5373%
5374% o exception: return any errors or warnings in this structure.
5375%
5376*/
5377static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5378 NexusInfo *nexus_info,ExceptionInfo *exception)
5379{
5380 MagickOffsetType
5381 count,
5382 offset;
5383
5384 MagickSizeType
5385 length,
5386 number_pixels;
5387
cristy3ed852e2009-09-05 21:47:34 +00005388 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005389 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005390
cristy25ffffb2009-12-07 17:15:07 +00005391 register long
5392 y;
5393
cristy3ed852e2009-09-05 21:47:34 +00005394 unsigned long
5395 rows;
5396
5397 if (cache_info->debug != MagickFalse)
5398 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5399 cache_info->filename);
5400 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5401 return(MagickTrue);
5402 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5403 nexus_info->region.x;
5404 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5405 rows=nexus_info->region.height;
5406 number_pixels=length*rows;
5407 if ((cache_info->columns == nexus_info->region.width) &&
5408 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5409 {
5410 length=number_pixels;
5411 rows=1UL;
5412 }
5413 p=nexus_info->pixels;
5414 switch (cache_info->type)
5415 {
5416 case MemoryCache:
5417 case MapCache:
5418 {
5419 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005420 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005421
5422 /*
5423 Write pixels to memory.
5424 */
5425 q=cache_info->pixels+offset;
5426 for (y=0; y < (long) rows; y++)
5427 {
5428 (void) CopyMagickMemory(q,p,(size_t) length);
5429 p+=nexus_info->region.width;
5430 q+=cache_info->columns;
5431 }
5432 break;
5433 }
5434 case DiskCache:
5435 {
5436 /*
5437 Write pixels to disk.
5438 */
5439 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5440 {
5441 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5442 cache_info->cache_filename);
5443 return(MagickFalse);
5444 }
5445 for (y=0; y < (long) rows; y++)
5446 {
5447 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5448 sizeof(*p),length,(const unsigned char *) p);
5449 if ((MagickSizeType) count < length)
5450 break;
5451 p+=nexus_info->region.width;
5452 offset+=cache_info->columns;
5453 }
5454 if (y < (long) rows)
5455 {
5456 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5457 cache_info->cache_filename);
5458 return(MagickFalse);
5459 }
5460 break;
5461 }
5462 default:
5463 break;
5464 }
5465 if ((cache_info->debug != MagickFalse) &&
5466 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5467 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5468 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5469 nexus_info->region.x,nexus_info->region.y);
5470 return(MagickTrue);
5471}