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