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