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